revamp the way resume data is read, by providing a function for the client to parse resume data, capturing it in add_torrent_params
This commit is contained in:
parent
1710b7c750
commit
197ded5a0d
|
@ -1,3 +1,5 @@
|
||||||
|
* added new read_resume_data() function, initializing add_torrent_params
|
||||||
|
* removed deprecated fields from add_torrent_params
|
||||||
* improved support for bind-to-device
|
* improved support for bind-to-device
|
||||||
* deprecated ssl_listen, SSL sockets are specified in listen_interfaces now
|
* deprecated ssl_listen, SSL sockets are specified in listen_interfaces now
|
||||||
* improved support for listening on multiple sockets and interfaces
|
* improved support for listening on multiple sockets and interfaces
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -606,6 +606,7 @@ SOURCES =
|
||||||
proxy_base
|
proxy_base
|
||||||
puff
|
puff
|
||||||
random
|
random
|
||||||
|
read_resume_data
|
||||||
receive_buffer
|
receive_buffer
|
||||||
resolve_links
|
resolve_links
|
||||||
rss
|
rss
|
||||||
|
|
|
@ -35,7 +35,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||||
|
|
||||||
#include "libtorrent/storage_defs.hpp"
|
#include "libtorrent/storage_defs.hpp"
|
||||||
#include "libtorrent/peer_id.hpp" // sha1_hash
|
#include "libtorrent/peer_id.hpp" // sha1_hash
|
||||||
|
@ -75,53 +78,26 @@ namespace libtorrent
|
||||||
// data for the torrent. For more information, see the ``storage`` field.
|
// data for the torrent. For more information, see the ``storage`` field.
|
||||||
add_torrent_params(storage_constructor_type sc = default_storage_constructor)
|
add_torrent_params(storage_constructor_type sc = default_storage_constructor)
|
||||||
: version(LIBTORRENT_VERSION_NUM)
|
: version(LIBTORRENT_VERSION_NUM)
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
, tracker_url(0)
|
|
||||||
#endif
|
|
||||||
, storage_mode(storage_mode_sparse)
|
, storage_mode(storage_mode_sparse)
|
||||||
, storage(sc)
|
, storage(sc)
|
||||||
, userdata(0)
|
, userdata(0)
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
, flags(flag_ignore_flags | default_flags)
|
|
||||||
#else
|
|
||||||
, flags(default_flags)
|
, flags(default_flags)
|
||||||
#endif
|
|
||||||
, max_uploads(-1)
|
, max_uploads(-1)
|
||||||
, max_connections(-1)
|
, max_connections(-1)
|
||||||
, upload_limit(-1)
|
, upload_limit(-1)
|
||||||
, download_limit(-1)
|
, download_limit(-1)
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
, total_uploaded(0)
|
||||||
, seed_mode(false)
|
, total_downloaded(0)
|
||||||
, override_resume_data(false)
|
, active_time(0)
|
||||||
, upload_mode(false)
|
, finished_time(0)
|
||||||
, share_mode(false)
|
, seeding_time(0)
|
||||||
, apply_ip_filter(true)
|
, added_time(0)
|
||||||
, paused(true)
|
, completed_time(0)
|
||||||
, auto_managed(true)
|
, last_seen_complete(0)
|
||||||
, duplicate_is_error(false)
|
, num_complete(-1)
|
||||||
, merge_resume_trackers(false)
|
, num_incomplete(-1)
|
||||||
#endif
|
, num_downloaded(-1)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
void update_flags() const
|
|
||||||
{
|
|
||||||
if (flags != (flag_ignore_flags | default_flags)) return;
|
|
||||||
|
|
||||||
boost::uint64_t& f = const_cast<boost::uint64_t&>(flags);
|
|
||||||
f = flag_update_subscribe;
|
|
||||||
if (seed_mode) f |= flag_seed_mode;
|
|
||||||
if (override_resume_data) f |= flag_override_resume_data;
|
|
||||||
if (upload_mode) f |= flag_upload_mode;
|
|
||||||
if (share_mode) f |= flag_share_mode;
|
|
||||||
if (apply_ip_filter) f |= flag_apply_ip_filter;
|
|
||||||
if (paused) f |= flag_paused;
|
|
||||||
if (auto_managed) f |= flag_auto_managed;
|
|
||||||
if (duplicate_is_error) f |= flag_duplicate_is_error;
|
|
||||||
if (merge_resume_trackers) f |= flag_merge_resume_trackers;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// values for the ``flags`` field
|
// values for the ``flags`` field
|
||||||
enum flags_t
|
enum flags_t
|
||||||
|
@ -230,6 +206,8 @@ namespace libtorrent
|
||||||
// replaced by any trackers in the resume data. The default behavior is
|
// replaced by any trackers in the resume data. The default behavior is
|
||||||
// to have the resume data override the .torrent file _and_ the
|
// to have the resume data override the .torrent file _and_ the
|
||||||
// trackers added in add_torrent_params.
|
// trackers added in add_torrent_params.
|
||||||
|
//#error this needs to change slightly. Should trackers be extracted from the \
|
||||||
|
.torrent file on the client side? when in that case?
|
||||||
flag_merge_resume_trackers = 0x100,
|
flag_merge_resume_trackers = 0x100,
|
||||||
|
|
||||||
// on by default and means that this torrent will be part of state
|
// on by default and means that this torrent will be part of state
|
||||||
|
@ -247,10 +225,12 @@ namespace libtorrent
|
||||||
// the torrent handle immediately after adding it.
|
// the torrent handle immediately after adding it.
|
||||||
flag_sequential_download = 0x800,
|
flag_sequential_download = 0x800,
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// if this flag is set, the save path from the resume data file, if
|
// if this flag is set, the save path from the resume data file, if
|
||||||
// present, is honored. This defaults to not being set, in which
|
// present, is honored. This defaults to not being set, in which
|
||||||
// case the save_path specified in add_torrent_params is always used.
|
// case the save_path specified in add_torrent_params is always used.
|
||||||
flag_use_resume_save_path = 0x1000,
|
flag_use_resume_save_path = 0x1000,
|
||||||
|
#endif
|
||||||
|
|
||||||
// indicates that this torrent should never be unloaded from RAM, even
|
// indicates that this torrent should never be unloaded from RAM, even
|
||||||
// if unloading torrents are allowed in general. Setting this makes
|
// if unloading torrents are allowed in general. Setting this makes
|
||||||
|
@ -265,6 +245,8 @@ namespace libtorrent
|
||||||
// add_torrent_params are also replaced. The default behavior is to
|
// add_torrent_params are also replaced. The default behavior is to
|
||||||
// have any web seeds in the resume data take precedence over whatever
|
// have any web seeds in the resume data take precedence over whatever
|
||||||
// is passed in here as well as the .torrent file.
|
// is passed in here as well as the .torrent file.
|
||||||
|
//#error this needs to change slightly. Should web seeds be extracted from the \
|
||||||
|
.torrent file on the client side? when in that case?
|
||||||
flag_merge_resume_http_seeds = 0x2000,
|
flag_merge_resume_http_seeds = 0x2000,
|
||||||
|
|
||||||
// the stop when ready flag. Setting this flag is equivalent to calling
|
// the stop when ready flag. Setting this flag is equivalent to calling
|
||||||
|
@ -273,11 +255,7 @@ namespace libtorrent
|
||||||
flag_stop_when_ready = 0x4000,
|
flag_stop_when_ready = 0x4000,
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
default_flags = flag_pinned | flag_update_subscribe | flag_auto_managed | flag_paused | flag_apply_ip_filter
|
default_flags = flag_merge_resume_http_seeds | flag_merge_resume_trackers | flag_pinned | flag_update_subscribe | flag_auto_managed | flag_paused | flag_apply_ip_filter
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
, flag_ignore_flags = 0x80000000
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// filled in by the constructor and should be left untouched. It is used
|
// filled in by the constructor and should be left untouched. It is used
|
||||||
|
@ -287,13 +265,17 @@ namespace libtorrent
|
||||||
// info_hash is set, this is required to be initialized.
|
// info_hash is set, this is required to be initialized.
|
||||||
boost::shared_ptr<torrent_info> ti;
|
boost::shared_ptr<torrent_info> ti;
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
char const* tracker_url;
|
|
||||||
#endif
|
|
||||||
// If the torrent doesn't have a tracker, but relies on the DHT to find
|
// If the torrent doesn't have a tracker, but relies on the DHT to find
|
||||||
// peers, the ``trackers`` can specify tracker URLs for the torrent.
|
// peers, the ``trackers`` can specify tracker URLs for the torrent.
|
||||||
std::vector<std::string> trackers;
|
std::vector<std::string> trackers;
|
||||||
|
|
||||||
|
// the tiers the URLs in ``trackers`` belong to. Trackers belonging to
|
||||||
|
// different tiers may be treated differently, as defined by the multi
|
||||||
|
// tracker extension. This is optional, if not specified trackers are
|
||||||
|
// assumed to be part of tier 0, or whichever the last tier was as
|
||||||
|
// iterating over the trackers.
|
||||||
|
std::vector<int> tracker_tiers;
|
||||||
|
|
||||||
// url seeds to be added to the torrent (`BEP 17`_).
|
// url seeds to be added to the torrent (`BEP 17`_).
|
||||||
std::vector<std::string> url_seeds;
|
std::vector<std::string> url_seeds;
|
||||||
|
|
||||||
|
@ -302,10 +284,7 @@ namespace libtorrent
|
||||||
std::vector<std::pair<std::string, int> > dht_nodes;
|
std::vector<std::pair<std::string, int> > dht_nodes;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
// the path where the torrent is or will be stored. Note that this may
|
// the path where the torrent is or will be stored.
|
||||||
// also be stored in resume data. If you want the save path saved in
|
|
||||||
// the resume data to be used, you need to set the
|
|
||||||
// flag_use_resume_save_path flag.
|
|
||||||
//
|
//
|
||||||
// .. note::
|
// .. note::
|
||||||
// On windows this path (and other paths) are interpreted as UNC
|
// On windows this path (and other paths) are interpreted as UNC
|
||||||
|
@ -313,6 +292,9 @@ namespace libtorrent
|
||||||
// and may not contain the special directories "." or "..".
|
// and may not contain the special directories "." or "..".
|
||||||
std::string save_path;
|
std::string save_path;
|
||||||
|
|
||||||
|
#error do we still need this? what's left in the resume data that isn't parsed \
|
||||||
|
out into add_torrent_params? should it be moved to add_torrent_params?
|
||||||
|
|
||||||
// The optional parameter, ``resume_data`` can be given if up to date
|
// The optional parameter, ``resume_data`` can be given if up to date
|
||||||
// fast-resume data is available. The fast-resume data can be acquired
|
// fast-resume data is available. The fast-resume data can be acquired
|
||||||
// from a running torrent by calling save_resume_data() on
|
// from a running torrent by calling save_resume_data() on
|
||||||
|
@ -398,18 +380,45 @@ namespace libtorrent
|
||||||
int upload_limit;
|
int upload_limit;
|
||||||
int download_limit;
|
int download_limit;
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
// the total number of bytes uploaded and downloaded by this torrent so
|
||||||
bool seed_mode;
|
// far.
|
||||||
bool override_resume_data;
|
boost::int64_t total_uploaded;
|
||||||
bool upload_mode;
|
boost::int64_t total_downloaded;
|
||||||
bool share_mode;
|
|
||||||
bool apply_ip_filter;
|
|
||||||
bool paused;
|
|
||||||
bool auto_managed;
|
|
||||||
bool duplicate_is_error;
|
|
||||||
bool merge_resume_trackers;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// the numeber of seconds this torrent has spent in started, finished and
|
||||||
|
// seeding state so far, respectively.
|
||||||
|
int active_time;
|
||||||
|
int finished_time;
|
||||||
|
int seeding_time;
|
||||||
|
|
||||||
|
// if set to a non-zero value, this is the posix time of when this torrent
|
||||||
|
// was first added, including previous runs/sessions. If set to zero, the
|
||||||
|
// internal added_time will be set to the time of when add_torrent() is
|
||||||
|
// called.
|
||||||
|
time_t added_time;
|
||||||
|
time_t completed_time;
|
||||||
|
|
||||||
|
// if set to non-zero, initializes the time (expressed in posix time) when
|
||||||
|
// we last saw a seed or peers that together formed a complete copy of the
|
||||||
|
// torrent. If left set to zero, the internal counterpart to this field
|
||||||
|
// will be updated when we see a seed or a distributed copies >= 1.0.
|
||||||
|
time_t last_seen_complete;
|
||||||
|
|
||||||
|
// these field can be used to initialize the torrent's cached scrape data.
|
||||||
|
// The scrape data is high level metadata about the current state of the
|
||||||
|
// swarm, as returned by the tracker (either when announcing to it or by
|
||||||
|
// sending a specific scrape request). ``num_complete`` is the number of
|
||||||
|
// peers in the swarm that are seeds, or have every piece in the torrent.
|
||||||
|
// ``num_inomplete`` is the number of peers in the swarm that do not have
|
||||||
|
// every piece. ``num_downloaded`` is the number of times the torrent has
|
||||||
|
// been downloaded (not initiated, but the number of times a download has
|
||||||
|
// completed).
|
||||||
|
//
|
||||||
|
// Leaving any of these values set to -1 indicates we don't know, or we
|
||||||
|
// have not received any scrape data.
|
||||||
|
int num_complete;
|
||||||
|
int num_incomplete;
|
||||||
|
int num_downloaded;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ TORRENT_EXPORT std::string print_entry(bdecode_node const& e
|
||||||
// produced by this function does not copy any data out of the buffer, but
|
// produced by this function does not copy any data out of the buffer, but
|
||||||
// simply produces references back into it.
|
// simply produces references back into it.
|
||||||
TORRENT_EXPORT int bdecode(char const* start, char const* end, bdecode_node& ret
|
TORRENT_EXPORT int bdecode(char const* start, char const* end, bdecode_node& ret
|
||||||
, error_code& ec, int* error_pos = 0, int depth_limit = 100
|
, error_code& ec, int* error_pos = NULL, int depth_limit = 100
|
||||||
, int token_limit = 1000000);
|
, int token_limit = 1000000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2015, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_READ_RESUME_DATA_HPP_INCLUDE
|
||||||
|
#define TORRENT_READ_RESUME_DATA_HPP_INCLUDE
|
||||||
|
|
||||||
|
#include "libtorrent/error_code.hpp"
|
||||||
|
#include "libtorrent/export.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
struct add_torrent_params;
|
||||||
|
struct bdecode_node;
|
||||||
|
|
||||||
|
// these functions are used to parse resume data and populate the appropriate
|
||||||
|
// fields in an add_torrent_param object. This object can then be used to add
|
||||||
|
// the actual torrent_info object to and pass to session::add_torrent() or
|
||||||
|
// session::async_add_torrent()
|
||||||
|
TORRENT_EXPORT add_torrent_params read_resume_data(bdecode_node const& rd
|
||||||
|
, error_code& ec);
|
||||||
|
TORRENT_EXPORT add_torrent_params read_resume_data(char const* buffer
|
||||||
|
, int size, error_code& ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -989,7 +989,6 @@ namespace libtorrent
|
||||||
torrent_handle get_handle();
|
torrent_handle get_handle();
|
||||||
|
|
||||||
void write_resume_data(entry& rd) const;
|
void write_resume_data(entry& rd) const;
|
||||||
void read_resume_data(bdecode_node const& rd);
|
|
||||||
|
|
||||||
void seen_complete() { m_last_seen_complete = time(0); }
|
void seen_complete() { m_last_seen_complete = time(0); }
|
||||||
int time_since_complete() const { return int(time(0) - m_last_seen_complete); }
|
int time_since_complete() const { return int(time(0) - m_last_seen_complete); }
|
||||||
|
@ -1306,6 +1305,7 @@ namespace libtorrent
|
||||||
error_code m_error;
|
error_code m_error;
|
||||||
|
|
||||||
// used if there is any resume data
|
// used if there is any resume data
|
||||||
|
#error do we still need this?
|
||||||
boost::scoped_ptr<resume_data_t> m_resume_data;
|
boost::scoped_ptr<resume_data_t> m_resume_data;
|
||||||
|
|
||||||
// if the torrent is started without metadata, it may
|
// if the torrent is started without metadata, it may
|
||||||
|
@ -1494,9 +1494,7 @@ namespace libtorrent
|
||||||
// torrent.
|
// torrent.
|
||||||
bool m_super_seeding:1;
|
bool m_super_seeding:1;
|
||||||
|
|
||||||
// this is set when we don't want to load seed_mode,
|
#error a 1 bit hole here
|
||||||
// paused or auto_managed from the resume data
|
|
||||||
const bool m_override_resume_data:1;
|
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||||
|
@ -1689,14 +1687,7 @@ namespace libtorrent
|
||||||
// quarantine
|
// quarantine
|
||||||
bool m_pending_active_change:1;
|
bool m_pending_active_change:1;
|
||||||
|
|
||||||
// if this is set, accept the save path saved in the resume data, if
|
#error 2 missing bit here
|
||||||
// present
|
|
||||||
bool m_use_resume_save_path:1;
|
|
||||||
|
|
||||||
// if set to true, add web seed URLs loaded from resume
|
|
||||||
// data into this torrent instead of replacing the ones from the .torrent
|
|
||||||
// file
|
|
||||||
bool m_merge_resume_http_seeds:1;
|
|
||||||
|
|
||||||
// if this is set, whenever transitioning into a downloading/seeding state
|
// if this is set, whenever transitioning into a downloading/seeding state
|
||||||
// from a non-downloading/seeding state, the torrent is paused.
|
// from a non-downloading/seeding state, the torrent is paused.
|
||||||
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2015, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||||
|
|
||||||
|
#include "libtorrent/bdecode.hpp"
|
||||||
|
#include "libtorrent/read_resume_data.hpp"
|
||||||
|
#include "libtorrent/add_torrent_params.hpp"
|
||||||
|
#include "libtorrent/announce_entry.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void apply_flag(boost::uint64_t& current_flags
|
||||||
|
, bdecode_node const& n
|
||||||
|
, char const* name
|
||||||
|
, boost::uint64_t const flag)
|
||||||
|
{
|
||||||
|
if (n.dict_find_int_value(name, -1) == -1)
|
||||||
|
{
|
||||||
|
current_flags &= ~flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_flags |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_torrent_params read_resume_data(bdecode_node const& rd, error_code& ec)
|
||||||
|
{
|
||||||
|
add_torrent_params ret;
|
||||||
|
|
||||||
|
ret.total_uploaded = rd.dict_find_int_value("total_uploaded");
|
||||||
|
ret.total_downloaded = rd.dict_find_int_value("total_downloaded");
|
||||||
|
ret.active_time = rd.dict_find_int_value("active_time");
|
||||||
|
ret.finished_time = rd.dict_find_int_value("finished_time");
|
||||||
|
ret.seeding_time = rd.dict_find_int_value("seeding_time");
|
||||||
|
|
||||||
|
ret.last_seen_complete = rd.dict_find_int_value("last_seen_complete");
|
||||||
|
|
||||||
|
// scrape data cache
|
||||||
|
ret.num_complete = rd.dict_find_int_value("num_complete", -1);
|
||||||
|
ret.num_incomplete = rd.dict_find_int_value("num_incomplete", -1);
|
||||||
|
ret.num_downloaded = rd.dict_find_int_value("num_downloaded", -1);
|
||||||
|
|
||||||
|
// torrent settings
|
||||||
|
ret.max_uploads = rd.dict_find_int_value("max_uploads", -1);
|
||||||
|
ret.max_connections = rd.dict_find_int_value("max_connections", -1);
|
||||||
|
ret.upload_limit = rd.dict_find_int_value("upload_rate_limit", -1);
|
||||||
|
ret.download_limit = rd.dict_find_int_value("download_rate_limit", -1);
|
||||||
|
|
||||||
|
// torrent state
|
||||||
|
apply_flag(ret.flags, rd, "seed_mode", add_torrent_params::flag_seed_mode);
|
||||||
|
apply_flag(ret.flags, rd, "super_seeding", add_torrent_params::flag_super_seeding);
|
||||||
|
apply_flag(ret.flags, rd, "auto_managed", add_torrent_params::flag_auto_managed);
|
||||||
|
apply_flag(ret.flags, rd, "sequential_download", add_torrent_params::flag_sequential_download);
|
||||||
|
apply_flag(ret.flags, rd, "paused", add_torrent_params::flag_paused);
|
||||||
|
|
||||||
|
ret.save_path = rd.dict_find_string_value("save_path");
|
||||||
|
|
||||||
|
ret.url = rd.dict_find_string_value("url");
|
||||||
|
ret.uuid = rd.dict_find_string_value("uuid");
|
||||||
|
ret.source_feed_url = rd.dict_find_string_value("feed");
|
||||||
|
|
||||||
|
#error add a field for this. The mapping has to happen in the torrent \
|
||||||
|
constructor probably, and passed on to the storage. possibly, the \
|
||||||
|
mapped_storage should be passed directly in when the storage is constructed
|
||||||
|
|
||||||
|
bdecode_node mapped_files = rd.dict_find_list("mapped_files");
|
||||||
|
if (mapped_files && mapped_files.list_size() == m_torrent_file->num_files())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_torrent_file->num_files(); ++i)
|
||||||
|
{
|
||||||
|
std::string new_filename = mapped_files.list_string_value_at(i);
|
||||||
|
if (new_filename.empty()) continue;
|
||||||
|
m_torrent_file->rename_file(i, new_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.added_time = rd.dict_find_int_value("added_time", 0);
|
||||||
|
ret.completed_time = rd.dict_find_int_value("completed_time", 0);
|
||||||
|
|
||||||
|
// load file priorities except if the add_torrent_param file was set to
|
||||||
|
// override resume data
|
||||||
|
bdecode_node file_priority = rd.dict_find_list("file_priority");
|
||||||
|
if (file_priority)
|
||||||
|
{
|
||||||
|
const int num_files = file_priority.list_size();
|
||||||
|
ret.file_priorities.resize(num_files, 4);
|
||||||
|
for (int i = 0; i < num_files; ++i)
|
||||||
|
{
|
||||||
|
ret.file_priorities[i] = file_priority.list_int_value_at(i, 1);
|
||||||
|
// this is suspicious, leave seed mode
|
||||||
|
if (ret.file_priorities[i] == 0)
|
||||||
|
{
|
||||||
|
ret.flags &= ~add_torrent_params::flag_seed_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bdecode_node trackers = rd.dict_find_list("trackers");
|
||||||
|
if (trackers)
|
||||||
|
{
|
||||||
|
// it's possible to delete the trackers from a torrent and then save
|
||||||
|
// resume data with an empty trackers list. Since we found a trackers
|
||||||
|
// list here, these should replace whatever we find in the .torrent
|
||||||
|
// file.
|
||||||
|
ret.flags &= ~add_torrent_params::flag_merge_resume_trackers;
|
||||||
|
|
||||||
|
int tier = 0;
|
||||||
|
for (int i = 0; i < trackers.list_size(); ++i)
|
||||||
|
{
|
||||||
|
bdecode_node tier_list = trackers.list_at(i);
|
||||||
|
if (!tier_list || tier_list.type() != bdecode_node::list_t)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < tier_list.list_size(); ++j)
|
||||||
|
{
|
||||||
|
ret.trackers.push_back(tier_list.list_string_value_at(j));
|
||||||
|
ret.tracker_tiers.push_back(tier);
|
||||||
|
}
|
||||||
|
++tier;
|
||||||
|
}
|
||||||
|
std::sort(m_trackers.begin(), m_trackers.end(), boost::bind(&announce_entry::tier, _1)
|
||||||
|
< boost::bind(&announce_entry::tier, _2));
|
||||||
|
|
||||||
|
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
||||||
|
prioritize_udp_trackers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if merge resume http seeds is not set, we need to clear whatever web
|
||||||
|
// seeds we loaded from the .torrent file, because we want whatever's in
|
||||||
|
// the resume file to take precedence. If there aren't even any fields in
|
||||||
|
// the resume data though, keep the ones from the torrent
|
||||||
|
bdecode_node url_list = rd.dict_find_list("url-list");
|
||||||
|
bdecode_node httpseeds = rd.dict_find_list("httpseeds");
|
||||||
|
if ((url_list || httpseeds) && !m_merge_resume_http_seeds)
|
||||||
|
{
|
||||||
|
// since we found http seeds in the resume data, they should replace
|
||||||
|
// whatever web seeds are specified in the .torrent
|
||||||
|
ret.flags &= ~add_torrent_params::flag_merge_resume_http_seeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url_list)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < url_list.list_size(); ++i)
|
||||||
|
{
|
||||||
|
std::string url = url_list.list_string_value_at(i);
|
||||||
|
if (url.empty()) continue;
|
||||||
|
ret.url_seeds.push_back(url);
|
||||||
|
|
||||||
|
#error this correction logic has to be moved to the torrent constructor now
|
||||||
|
if (m_torrent_file->num_files() > 1 && url[url.size()-1] != '/') url += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpseeds)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < httpseeds.list_size(); ++i)
|
||||||
|
{
|
||||||
|
std::string url = httpseeds.list_string_value_at(i);
|
||||||
|
if (url.empty()) continue;
|
||||||
|
#error add this field (merge with url_seeds?)
|
||||||
|
ret.http_seeds.push_back(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bdecode_node mt = rd.dict_find_string("merkle tree");
|
||||||
|
if (mt)
|
||||||
|
{
|
||||||
|
#error add field for this
|
||||||
|
std::vector<sha1_hash> tree;
|
||||||
|
tree.resize(m_torrent_file->merkle_tree().size());
|
||||||
|
std::memcpy(&tree[0], mt.string_ptr()
|
||||||
|
, (std::min)(mt.string_length(), int(tree.size()) * 20));
|
||||||
|
if (mt.string_length() < int(tree.size()) * 20)
|
||||||
|
std::memset(&tree[0] + mt.string_length() / 20, 0
|
||||||
|
, tree.size() - mt.string_length() / 20);
|
||||||
|
m_torrent_file->set_merkle_tree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#error this is the case where the torrent is a merkle torrent but the resume \
|
||||||
|
data does not contain the merkle tree, we need some kind of check in the \
|
||||||
|
torrent constructor and error reporting
|
||||||
|
{
|
||||||
|
// TODO: 0 if this is a merkle torrent and we can't
|
||||||
|
// restore the tree, we need to wipe all the
|
||||||
|
// bits in the have array, but not necessarily
|
||||||
|
// we might want to do a full check to see if we have
|
||||||
|
// all the pieces. This is low priority since almost
|
||||||
|
// no one uses merkle torrents
|
||||||
|
TORRENT_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#error add fields to add_torrent_params for these
|
||||||
|
// some sanity checking. Maybe we shouldn't be in seed mode anymore
|
||||||
|
bdecode_node pieces = rd.dict_find("pieces");
|
||||||
|
if (pieces && pieces.type() == bdecode_node::string_t
|
||||||
|
&& int(pieces.string_length()) == m_torrent_file->num_pieces())
|
||||||
|
{
|
||||||
|
char const* pieces_str = pieces.string_ptr();
|
||||||
|
for (int i = 0, end(pieces.string_length()); i < end; ++i)
|
||||||
|
{
|
||||||
|
// being in seed mode and missing a piece is not compatible.
|
||||||
|
// Leave seed mode if that happens
|
||||||
|
if ((pieces_str[i] & 1)) continue;
|
||||||
|
m_seed_mode = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bdecode_node piece_priority = rd.dict_find_string("piece_priority");
|
||||||
|
if (piece_priority && piece_priority.string_length()
|
||||||
|
== m_torrent_file->num_pieces())
|
||||||
|
{
|
||||||
|
char const* p = piece_priority.string_ptr();
|
||||||
|
for (int i = 0; i < piece_priority.string_length(); ++i)
|
||||||
|
{
|
||||||
|
if (p[i] > 0) continue;
|
||||||
|
m_seed_mode = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_verified.resize(m_torrent_file->num_pieces(), false);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_torrent_params read_resume_data(char const* buffer, int size, error_code& ec)
|
||||||
|
{
|
||||||
|
bdecode_node rd;
|
||||||
|
bdecode(buffer, buffer + size, rd, ec);
|
||||||
|
if (ec) return add_torrent_params();
|
||||||
|
|
||||||
|
return read_resume_data(rd, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace libtorrent
|
||||||
return TORRENT_SYNC_CALL_RET(std::vector<torrent_handle>, get_torrents);
|
return TORRENT_SYNC_CALL_RET(std::vector<torrent_handle>, get_torrents);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
torrent_handle session_handle::add_torrent(add_torrent_params const& params)
|
torrent_handle session_handle::add_torrent(add_torrent_params const& params)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
|
@ -171,13 +171,11 @@ namespace libtorrent
|
||||||
void session_handle::async_add_torrent(add_torrent_params const& params)
|
void session_handle::async_add_torrent(add_torrent_params const& params)
|
||||||
{
|
{
|
||||||
add_torrent_params* p = new add_torrent_params(params);
|
add_torrent_params* p = new add_torrent_params(params);
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#error all add_torrent() and async_add_torrent() function need to pass the \
|
||||||
if (params.tracker_url)
|
add_torrent_params through a function that parses the resume vector and \
|
||||||
{
|
blends the results into the params object (unless deprecated functions \
|
||||||
p->trackers.push_back(params.tracker_url);
|
are disabled)
|
||||||
p->tracker_url = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
TORRENT_ASYNC_CALL1(async_add_torrent, p);
|
TORRENT_ASYNC_CALL1(async_add_torrent, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,11 +215,14 @@ namespace libtorrent
|
||||||
, void* userdata)
|
, void* userdata)
|
||||||
{
|
{
|
||||||
add_torrent_params p(sc);
|
add_torrent_params p(sc);
|
||||||
p.tracker_url = tracker_url;
|
p.trackers.push_back(tracker_url);
|
||||||
p.info_hash = info_hash;
|
p.info_hash = info_hash;
|
||||||
p.save_path = save_path;
|
p.save_path = save_path;
|
||||||
p.storage_mode = storage_mode;
|
p.storage_mode = storage_mode;
|
||||||
p.paused = paused;
|
|
||||||
|
if (paused) p.flags |= add_torrent_params::flag_paused;
|
||||||
|
else p.flags &= ~add_torrent_params::flag_paused;
|
||||||
|
|
||||||
p.userdata = userdata;
|
p.userdata = userdata;
|
||||||
p.name = name;
|
p.name = name;
|
||||||
if (resume_data.type() != entry::undefined_t)
|
if (resume_data.type() != entry::undefined_t)
|
||||||
|
|
|
@ -4615,10 +4615,6 @@ namespace aux {
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(!p.save_path.empty());
|
TORRENT_ASSERT(!p.save_path.empty());
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
p.update_flags();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
add_torrent_params params = p;
|
add_torrent_params params = p;
|
||||||
if (string_begins_no_case("magnet:", params.url.c_str()))
|
if (string_begins_no_case("magnet:", params.url.c_str()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -820,6 +820,18 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool is_seed(char const* pieces, int const len)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
if ((pieces[i] & 1) == 0) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool default_storage::verify_resume_data(bdecode_node const& rd
|
bool default_storage::verify_resume_data(bdecode_node const& rd
|
||||||
, std::vector<std::string> const* links
|
, std::vector<std::string> const* links
|
||||||
, storage_error& ec)
|
, storage_error& ec)
|
||||||
|
@ -868,6 +880,10 @@ namespace libtorrent
|
||||||
&& int(pieces.string_length()) == fs.num_pieces())
|
&& int(pieces.string_length()) == fs.num_pieces())
|
||||||
{
|
{
|
||||||
char const* pieces_str = pieces.string_ptr();
|
char const* pieces_str = pieces.string_ptr();
|
||||||
|
|
||||||
|
// TODO: this should just be a std::none_of()
|
||||||
|
bool const seed = is_seed(pieces_str, pieces.string_length());
|
||||||
|
|
||||||
// parse have bitmask. Verify that the files we expect to have
|
// parse have bitmask. Verify that the files we expect to have
|
||||||
// actually do exist
|
// actually do exist
|
||||||
for (int i = 0; i < fs.num_pieces(); ++i)
|
for (int i = 0; i < fs.num_pieces(); ++i)
|
||||||
|
@ -900,6 +916,16 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seed && size != fs.file_size(i))
|
||||||
|
{
|
||||||
|
// the resume data indicates we're a seed, but this file has
|
||||||
|
// the wrong size. Reject the resume data
|
||||||
|
ec.ec = errors::mismatching_file_size;
|
||||||
|
ec.file = i;
|
||||||
|
ec.operation = storage_error::check_resume;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// OK, this file existed, good. Now, skip all remaining pieces in
|
// OK, this file existed, good. Now, skip all remaining pieces in
|
||||||
// this file. We're just sanity-checking whether the files exist
|
// this file. We're just sanity-checking whether the files exist
|
||||||
// or not.
|
// or not.
|
||||||
|
@ -908,6 +934,13 @@ namespace libtorrent
|
||||||
i = (std::max)(i + 1, pr.piece);
|
i = (std::max)(i + 1, pr.piece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ec.ec = errors::missing_pieces;
|
||||||
|
ec.file = -1;
|
||||||
|
ec.operation = storage_error::check_resume;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
344
src/torrent.cpp
344
src/torrent.cpp
|
@ -237,7 +237,6 @@ namespace libtorrent
|
||||||
, m_auto_sequential(false)
|
, m_auto_sequential(false)
|
||||||
, m_seed_mode(false)
|
, m_seed_mode(false)
|
||||||
, m_super_seeding(false)
|
, m_super_seeding(false)
|
||||||
, m_override_resume_data((p.flags & add_torrent_params::flag_override_resume_data) != 0)
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||||
, m_resolving_country(false)
|
, m_resolving_country(false)
|
||||||
|
@ -278,8 +277,6 @@ namespace libtorrent
|
||||||
, m_last_scrape((std::numeric_limits<boost::int16_t>::min)())
|
, m_last_scrape((std::numeric_limits<boost::int16_t>::min)())
|
||||||
, m_progress_ppm(0)
|
, m_progress_ppm(0)
|
||||||
, m_pending_active_change(false)
|
, m_pending_active_change(false)
|
||||||
, m_use_resume_save_path((p.flags & add_torrent_params::flag_use_resume_save_path) != 0)
|
|
||||||
, m_merge_resume_http_seeds((p.flags & add_torrent_params::flag_merge_resume_http_seeds) != 0)
|
|
||||||
, m_stop_when_ready((p.flags & add_torrent_params::flag_stop_when_ready) != 0)
|
, m_stop_when_ready((p.flags & add_torrent_params::flag_stop_when_ready) != 0)
|
||||||
{
|
{
|
||||||
// we cannot log in the constructor, because it relies on shared_from_this
|
// we cannot log in the constructor, because it relies on shared_from_this
|
||||||
|
@ -357,6 +354,40 @@ namespace libtorrent
|
||||||
m_resume_data.reset(new resume_data_t);
|
m_resume_data.reset(new resume_data_t);
|
||||||
m_resume_data->buf = p.resume_data;
|
m_resume_data->buf = p.resume_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tier = 0;
|
||||||
|
std::vector<int>::const_iterator tier_iter = p.tracker_tiers.begin();
|
||||||
|
for (std::vector<std::string>::const_iterator i = p.trackers.begin()
|
||||||
|
, end(p.trackers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (tier_iter != p.tracker_tiers.end())
|
||||||
|
tier = *tier_iter++;
|
||||||
|
|
||||||
|
announce_entry e(*i);
|
||||||
|
e.fail_limit = 0;
|
||||||
|
e.source = announce_entry::source_magnet_link;
|
||||||
|
e.tier = tier;
|
||||||
|
m_trackers.push_back(e);
|
||||||
|
m_torrent_file->add_tracker(*i, tier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
||||||
|
prioritize_udp_trackers();
|
||||||
|
|
||||||
|
|
||||||
|
m_total_uploaded = p.total_uploaded;
|
||||||
|
m_total_downloaded = p.total_downloaded;
|
||||||
|
|
||||||
|
// the numeber of seconds this torrent has spent in started, finished and
|
||||||
|
// seeding state so far, respectively.
|
||||||
|
m_active_time = p.active_time;
|
||||||
|
m_finished_time = p.finished_time;
|
||||||
|
m_seeding_time = p.seeding_time;
|
||||||
|
|
||||||
|
m_added_time = p.added_time ? p.added_time : time(0);
|
||||||
|
m_completed_time = p.completed_time;
|
||||||
|
if (m_completed_time != 0 && m_completed_time < m_added_time)
|
||||||
|
m_completed_time = m_added_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::inc_stats_counter(int c, int value)
|
void torrent::inc_stats_counter(int c, int value)
|
||||||
|
@ -718,6 +749,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
||||||
|
#error why isn't this done in the constructor?
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
debug_log("creating torrent: %s max-uploads: %d max-connections: %d "
|
debug_log("creating torrent: %s max-uploads: %d max-connections: %d "
|
||||||
"upload-limit: %d download-limit: %d flags: %s%s%s%s%s%s%s%s%s%s%s%s"
|
"upload-limit: %d download-limit: %d flags: %s%s%s%s%s%s%s%s%s%s%s%s"
|
||||||
|
@ -770,28 +803,6 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url));
|
if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url));
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
if (p.tracker_url && std::strlen(p.tracker_url) > 0)
|
|
||||||
{
|
|
||||||
m_trackers.push_back(announce_entry(p.tracker_url));
|
|
||||||
m_trackers.back().fail_limit = 0;
|
|
||||||
m_trackers.back().source = announce_entry::source_magnet_link;
|
|
||||||
m_torrent_file->add_tracker(p.tracker_url);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator i = p.trackers.begin()
|
|
||||||
, end(p.trackers.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
m_trackers.push_back(announce_entry(*i));
|
|
||||||
m_trackers.back().fail_limit = 0;
|
|
||||||
m_trackers.back().source = announce_entry::source_magnet_link;
|
|
||||||
m_torrent_file->add_tracker(*i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
|
||||||
prioritize_udp_trackers();
|
|
||||||
|
|
||||||
// if we don't have metadata, make this torrent pinned. The
|
// if we don't have metadata, make this torrent pinned. The
|
||||||
// client may unpin it once we have metadata and it has had
|
// client may unpin it once we have metadata and it has had
|
||||||
// a chance to save it on the metadata_received_alert
|
// a chance to save it on the metadata_received_alert
|
||||||
|
@ -1808,7 +1819,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// this may not be called from a constructor because of the call to
|
// this may not be called from a constructor because of the call to
|
||||||
// shared_from_this()
|
// shared_from_this(). It's either called when we start() the torrent, or at a
|
||||||
|
// later time if it's a magnet link, once the metadata is downloaded
|
||||||
void torrent::init()
|
void torrent::init()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -1883,10 +1895,6 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
m_resume_data.reset();
|
m_resume_data.reset();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
read_resume_data(m_resume_data->node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
|
@ -1927,6 +1935,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// if we've already loaded file priorities, don't load piece priorities,
|
// if we've already loaded file priorities, don't load piece priorities,
|
||||||
// they will interfere.
|
// they will interfere.
|
||||||
|
#error we should get the piece priority from add_torrent_params instead
|
||||||
if (!m_seed_mode && m_resume_data && m_file_priority.empty())
|
if (!m_seed_mode && m_resume_data && m_file_priority.empty())
|
||||||
{
|
{
|
||||||
bdecode_node piece_priority = m_resume_data->node
|
bdecode_node piece_priority = m_resume_data->node
|
||||||
|
@ -6784,278 +6793,6 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
#endif // TORRENT_NO_DEPRECATE
|
#endif // TORRENT_NO_DEPRECATE
|
||||||
|
|
||||||
void torrent::read_resume_data(bdecode_node const& rd)
|
|
||||||
{
|
|
||||||
m_total_uploaded = rd.dict_find_int_value("total_uploaded");
|
|
||||||
m_total_downloaded = rd.dict_find_int_value("total_downloaded");
|
|
||||||
m_active_time = rd.dict_find_int_value("active_time");
|
|
||||||
m_finished_time = rd.dict_find_int_value("finished_time");
|
|
||||||
m_seeding_time = rd.dict_find_int_value("seeding_time");
|
|
||||||
m_last_seen_complete = rd.dict_find_int_value("last_seen_complete");
|
|
||||||
m_complete = rd.dict_find_int_value("num_complete", 0xffffff);
|
|
||||||
m_incomplete = rd.dict_find_int_value("num_incomplete", 0xffffff);
|
|
||||||
m_downloaded = rd.dict_find_int_value("num_downloaded", 0xffffff);
|
|
||||||
|
|
||||||
if (!m_override_resume_data)
|
|
||||||
{
|
|
||||||
int up_limit_ = rd.dict_find_int_value("upload_rate_limit", -1);
|
|
||||||
if (up_limit_ != -1) set_upload_limit(up_limit_);
|
|
||||||
|
|
||||||
int down_limit_ = rd.dict_find_int_value("download_rate_limit", -1);
|
|
||||||
if (down_limit_ != -1) set_download_limit(down_limit_);
|
|
||||||
|
|
||||||
int max_connections_ = rd.dict_find_int_value("max_connections", -1);
|
|
||||||
if (max_connections_ != -1) set_max_connections(max_connections_);
|
|
||||||
|
|
||||||
int max_uploads_ = rd.dict_find_int_value("max_uploads", -1);
|
|
||||||
if (max_uploads_ != -1) set_max_uploads(max_uploads_);
|
|
||||||
|
|
||||||
int seed_mode_ = rd.dict_find_int_value("seed_mode", -1);
|
|
||||||
if (seed_mode_ != -1) m_seed_mode = seed_mode_ && m_torrent_file->is_valid();
|
|
||||||
|
|
||||||
int super_seeding_ = rd.dict_find_int_value("super_seeding", -1);
|
|
||||||
if (super_seeding_ != -1) super_seeding(super_seeding_ != 0);
|
|
||||||
|
|
||||||
int auto_managed_ = rd.dict_find_int_value("auto_managed", -1);
|
|
||||||
if (auto_managed_ != -1)
|
|
||||||
{
|
|
||||||
m_auto_managed = auto_managed_ != 0;
|
|
||||||
|
|
||||||
update_want_scrape();
|
|
||||||
update_state_list();
|
|
||||||
}
|
|
||||||
|
|
||||||
int sequential_ = rd.dict_find_int_value("sequential_download", -1);
|
|
||||||
if (sequential_ != -1) set_sequential_download(sequential_ != 0);
|
|
||||||
|
|
||||||
int paused_ = rd.dict_find_int_value("paused", -1);
|
|
||||||
if (paused_ != -1)
|
|
||||||
{
|
|
||||||
set_allow_peers(paused_ == 0);
|
|
||||||
m_announce_to_dht = (paused_ == 0);
|
|
||||||
m_announce_to_trackers = (paused_ == 0);
|
|
||||||
m_announce_to_lsd = (paused_ == 0);
|
|
||||||
|
|
||||||
update_gauge();
|
|
||||||
update_want_peers();
|
|
||||||
update_want_scrape();
|
|
||||||
update_state_list();
|
|
||||||
}
|
|
||||||
int dht_ = rd.dict_find_int_value("announce_to_dht", -1);
|
|
||||||
if (dht_ != -1) m_announce_to_dht = (dht_ != 0);
|
|
||||||
int lsd_ = rd.dict_find_int_value("announce_to_lsd", -1);
|
|
||||||
if (lsd_ != -1) m_announce_to_lsd = (lsd_ != 0);
|
|
||||||
int track_ = rd.dict_find_int_value("announce_to_trackers", -1);
|
|
||||||
if (track_ != -1) m_announce_to_trackers = (track_ != 0);
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
debug_log("loaded resume data: max-uploads: %d max-connections: %d "
|
|
||||||
"upload-limit: %d download-limit: %d paused: %d sequential-download: %d "
|
|
||||||
"super-seeding: %d auto-managed: %d"
|
|
||||||
, max_uploads_, max_connections_, up_limit_, down_limit_
|
|
||||||
, paused_, sequential_, super_seeding_, auto_managed_);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int now = m_ses.session_time();
|
|
||||||
int tmp = rd.dict_find_int_value("last_scrape", -1);
|
|
||||||
m_last_scrape = tmp == -1 ? (std::numeric_limits<boost::int16_t>::min)() : now - tmp;
|
|
||||||
tmp = rd.dict_find_int_value("last_download", -1);
|
|
||||||
m_last_download = tmp == -1 ? (std::numeric_limits<boost::int16_t>::min)() : now - tmp;
|
|
||||||
tmp = rd.dict_find_int_value("last_upload", -1);
|
|
||||||
m_last_upload = tmp == -1 ? (std::numeric_limits<boost::int16_t>::min)() : now - tmp;
|
|
||||||
|
|
||||||
if (m_use_resume_save_path)
|
|
||||||
{
|
|
||||||
std::string p = rd.dict_find_string_value("save_path");
|
|
||||||
if (!p.empty())
|
|
||||||
{
|
|
||||||
m_save_path = p;
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
debug_log("loaded resume data: save-path: %s", m_save_path.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_url = rd.dict_find_string_value("url");
|
|
||||||
m_uuid = rd.dict_find_string_value("uuid");
|
|
||||||
m_source_feed_url = rd.dict_find_string_value("feed");
|
|
||||||
|
|
||||||
if (!m_uuid.empty() || !m_url.empty())
|
|
||||||
{
|
|
||||||
boost::shared_ptr<torrent> me(shared_from_this());
|
|
||||||
|
|
||||||
// insert this torrent in the uuid index
|
|
||||||
m_ses.insert_uuid_torrent(m_uuid.empty() ? m_url : m_uuid, me);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The mapped_files needs to be read both in the network thread
|
|
||||||
// and in the disk thread, since they both have their own mapped files structures
|
|
||||||
// which are kept in sync
|
|
||||||
bdecode_node mapped_files = rd.dict_find_list("mapped_files");
|
|
||||||
if (mapped_files && mapped_files.list_size() == m_torrent_file->num_files())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_torrent_file->num_files(); ++i)
|
|
||||||
{
|
|
||||||
std::string new_filename = mapped_files.list_string_value_at(i);
|
|
||||||
if (new_filename.empty()) continue;
|
|
||||||
m_torrent_file->rename_file(i, new_filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_added_time = rd.dict_find_int_value("added_time", m_added_time);
|
|
||||||
m_completed_time = rd.dict_find_int_value("completed_time", m_completed_time);
|
|
||||||
if (m_completed_time != 0 && m_completed_time < m_added_time)
|
|
||||||
m_completed_time = m_added_time;
|
|
||||||
|
|
||||||
// load file priorities except if the add_torrent_param file was set to
|
|
||||||
// override resume data
|
|
||||||
if (!m_override_resume_data || m_file_priority.empty())
|
|
||||||
{
|
|
||||||
bdecode_node file_priority = rd.dict_find_list("file_priority");
|
|
||||||
if (file_priority)
|
|
||||||
{
|
|
||||||
const int num_files = (std::min)(file_priority.list_size()
|
|
||||||
, m_torrent_file->num_files());
|
|
||||||
std::vector<int> file_prio(num_files);
|
|
||||||
for (int i = 0; i < num_files; ++i)
|
|
||||||
{
|
|
||||||
file_prio[i] = file_priority.list_int_value_at(i, 1);
|
|
||||||
// this is suspicious, leave seed mode
|
|
||||||
if (file_prio[i] == 0) m_seed_mode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
prioritize_files(file_prio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bdecode_node trackers = rd.dict_find_list("trackers");
|
|
||||||
if (trackers)
|
|
||||||
{
|
|
||||||
if (!m_merge_resume_trackers) m_trackers.clear();
|
|
||||||
int tier = 0;
|
|
||||||
for (int i = 0; i < trackers.list_size(); ++i)
|
|
||||||
{
|
|
||||||
bdecode_node tier_list = trackers.list_at(i);
|
|
||||||
if (!tier_list || tier_list.type() != bdecode_node::list_t)
|
|
||||||
continue;
|
|
||||||
for (int j = 0; j < tier_list.list_size(); ++j)
|
|
||||||
{
|
|
||||||
announce_entry e(tier_list.list_string_value_at(j));
|
|
||||||
if (std::find_if(m_trackers.begin(), m_trackers.end()
|
|
||||||
, boost::bind(&announce_entry::url, _1) == e.url) != m_trackers.end())
|
|
||||||
continue;
|
|
||||||
e.tier = tier;
|
|
||||||
e.fail_limit = 0;
|
|
||||||
m_trackers.push_back(e);
|
|
||||||
}
|
|
||||||
++tier;
|
|
||||||
}
|
|
||||||
std::sort(m_trackers.begin(), m_trackers.end(), boost::bind(&announce_entry::tier, _1)
|
|
||||||
< boost::bind(&announce_entry::tier, _2));
|
|
||||||
|
|
||||||
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
|
||||||
prioritize_udp_trackers();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if merge resume http seeds is not set, we need to clear whatever web
|
|
||||||
// seeds we loaded from the .torrent file, because we want whatever's in
|
|
||||||
// the resume file to take precedence. If there aren't even any fields in
|
|
||||||
// the resume data though, keep the ones from the torrent
|
|
||||||
bdecode_node url_list = rd.dict_find_list("url-list");
|
|
||||||
bdecode_node httpseeds = rd.dict_find_list("httpseeds");
|
|
||||||
if ((url_list || httpseeds) && !m_merge_resume_http_seeds)
|
|
||||||
{
|
|
||||||
m_web_seeds.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url_list)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < url_list.list_size(); ++i)
|
|
||||||
{
|
|
||||||
std::string url = url_list.list_string_value_at(i);
|
|
||||||
if (url.empty()) continue;
|
|
||||||
if (m_torrent_file->num_files() > 1 && url[url.size()-1] != '/') url += '/';
|
|
||||||
add_web_seed(url, web_seed_entry::url_seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (httpseeds)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < httpseeds.list_size(); ++i)
|
|
||||||
{
|
|
||||||
std::string url = httpseeds.list_string_value_at(i);
|
|
||||||
if (url.empty()) continue;
|
|
||||||
add_web_seed(url, web_seed_entry::http_seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_torrent_file->is_merkle_torrent())
|
|
||||||
{
|
|
||||||
bdecode_node mt = rd.dict_find_string("merkle tree");
|
|
||||||
if (mt)
|
|
||||||
{
|
|
||||||
std::vector<sha1_hash> tree;
|
|
||||||
tree.resize(m_torrent_file->merkle_tree().size());
|
|
||||||
std::memcpy(&tree[0], mt.string_ptr()
|
|
||||||
, (std::min)(mt.string_length(), int(tree.size()) * 20));
|
|
||||||
if (mt.string_length() < int(tree.size()) * 20)
|
|
||||||
std::memset(&tree[0] + mt.string_length() / 20, 0
|
|
||||||
, tree.size() - mt.string_length() / 20);
|
|
||||||
m_torrent_file->set_merkle_tree(tree);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: 0 if this is a merkle torrent and we can't
|
|
||||||
// restore the tree, we need to wipe all the
|
|
||||||
// bits in the have array, but not necessarily
|
|
||||||
// we might want to do a full check to see if we have
|
|
||||||
// all the pieces. This is low priority since almost
|
|
||||||
// no one uses merkle torrents
|
|
||||||
TORRENT_ASSERT(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updating some of the torrent state may have set need_save_resume_data.
|
|
||||||
// clear it here since we've just restored the resume data we already
|
|
||||||
// have. Nothing has changed from that state yet.
|
|
||||||
m_need_save_resume_data = false;
|
|
||||||
|
|
||||||
if (m_seed_mode)
|
|
||||||
{
|
|
||||||
// some sanity checking. Maybe we shouldn't be in seed mode anymore
|
|
||||||
bdecode_node pieces = rd.dict_find("pieces");
|
|
||||||
if (pieces && pieces.type() == bdecode_node::string_t
|
|
||||||
&& int(pieces.string_length()) == m_torrent_file->num_pieces())
|
|
||||||
{
|
|
||||||
char const* pieces_str = pieces.string_ptr();
|
|
||||||
for (int i = 0, end(pieces.string_length()); i < end; ++i)
|
|
||||||
{
|
|
||||||
// being in seed mode and missing a piece is not compatible.
|
|
||||||
// Leave seed mode if that happens
|
|
||||||
if ((pieces_str[i] & 1)) continue;
|
|
||||||
m_seed_mode = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bdecode_node piece_priority = rd.dict_find_string("piece_priority");
|
|
||||||
if (piece_priority && piece_priority.string_length()
|
|
||||||
== m_torrent_file->num_pieces())
|
|
||||||
{
|
|
||||||
char const* p = piece_priority.string_ptr();
|
|
||||||
for (int i = 0; i < piece_priority.string_length(); ++i)
|
|
||||||
{
|
|
||||||
if (p[i] > 0) continue;
|
|
||||||
m_seed_mode = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_verified.resize(m_torrent_file->num_pieces(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<const torrent_info> torrent::get_torrent_copy()
|
boost::shared_ptr<const torrent_info> torrent::get_torrent_copy()
|
||||||
{
|
{
|
||||||
if (!m_torrent_file->is_valid()) return boost::shared_ptr<const torrent_info>();
|
if (!m_torrent_file->is_valid()) return boost::shared_ptr<const torrent_info>();
|
||||||
|
@ -7372,9 +7109,6 @@ namespace libtorrent
|
||||||
ret["max_connections"] = max_connections();
|
ret["max_connections"] = max_connections();
|
||||||
ret["max_uploads"] = max_uploads();
|
ret["max_uploads"] = max_uploads();
|
||||||
ret["paused"] = is_torrent_paused();
|
ret["paused"] = is_torrent_paused();
|
||||||
ret["announce_to_dht"] = m_announce_to_dht;
|
|
||||||
ret["announce_to_trackers"] = m_announce_to_trackers;
|
|
||||||
ret["announce_to_lsd"] = m_announce_to_lsd;
|
|
||||||
ret["auto_managed"] = m_auto_managed;
|
ret["auto_managed"] = m_auto_managed;
|
||||||
|
|
||||||
// piece priorities and file priorities are mutually exclusive. If there
|
// piece priorities and file priorities are mutually exclusive. If there
|
||||||
|
|
Loading…
Reference in New Issue