support saving metadata in resume file, enable it by default for magnet links
This commit is contained in:
parent
56937edf56
commit
7288f77ec9
|
@ -1,3 +1,4 @@
|
|||
* support saving metadata in resume file, enable it by default for magnet links
|
||||
* support for receiving multi announce messages for local peer discovery
|
||||
* added session::listen_no_system_port flag to prevent libtorrent from ever binding the listen socket to port 0
|
||||
* added option to not recheck on missing or incomplete resume data
|
||||
|
|
|
@ -2134,6 +2134,7 @@ Its declaration looks like this::
|
|||
|
||||
std::string name() const;
|
||||
|
||||
enum save_resume_flags_t { flush_disk_cache = 1, save_info_dict = 2 };
|
||||
void save_resume_data(int flags = 0) const;
|
||||
bool need_save_resume_data() const;
|
||||
void force_reannounce() const;
|
||||
|
@ -2933,14 +2934,19 @@ save_resume_data()
|
|||
|
||||
::
|
||||
|
||||
enum save_resume_flags_t { flush_disk_cache = 1, save_info_dict = 2 };
|
||||
void save_resume_data(int flags = 0) const;
|
||||
|
||||
``save_resume_data()`` generates fast-resume data and returns it as an entry_. This entry_
|
||||
is suitable for being bencoded. For more information about how fast-resume works, see `fast resume`_.
|
||||
|
||||
The ``flags`` argument may be set to ``torrent_handle::flush_cache``. Doing so will flush the disk
|
||||
cache before creating the resume data. This avoids a problem with file timestamps in the resume
|
||||
data in case the cache hasn't been flushed yet.
|
||||
The ``flags`` argument is a bitmask of flags ORed together. If the flag ``torrent_handle::flush_cache``
|
||||
is set, the disk cache will be flushed before creating the resume data. This avoids a problem with
|
||||
file timestamps in the resume data in case the cache hasn't been flushed yet.
|
||||
|
||||
If the flag ``torrent_handle::save_info_dict`` is set, the resume data will contain the metadata
|
||||
from the torrent file as well. This is default for any torrent that's added without a torrent
|
||||
file (such as a magnet link or a URL).
|
||||
|
||||
This operation is asynchronous, ``save_resume_data`` will return immediately. The resume data
|
||||
is delivered when it's done through an `save_resume_data_alert`_.
|
||||
|
|
|
@ -671,7 +671,7 @@ void add_torrent(libtorrent::session& ses
|
|||
p.share_mode = share_mode;
|
||||
lazy_entry resume_data;
|
||||
|
||||
std::string filename = combine_path(save_path, ".resume/" + t->name() + ".resume");
|
||||
std::string filename = combine_path(save_path, ".resume/" + to_hex(t->info_hash().to_string()) + ".resume");
|
||||
|
||||
std::vector<char> buf;
|
||||
if (load_file(filename.c_str(), buf, ec) == 0)
|
||||
|
@ -845,7 +845,7 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
|
|||
{
|
||||
std::vector<char> out;
|
||||
bencode(std::back_inserter(out), *p->resume_data);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + h.name() + ".resume"), out);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + to_hex(h.info_hash().to_string()) + ".resume"), out);
|
||||
if (non_files.find(h) == non_files.end()
|
||||
&& std::find_if(files.begin(), files.end()
|
||||
, boost::bind(&handles_t::value_type::second, _1) == h) == files.end())
|
||||
|
@ -1211,6 +1211,26 @@ int main(int argc, char* argv[])
|
|||
p.storage_mode = (storage_mode_t)allocation_mode;
|
||||
p.url = *i;
|
||||
|
||||
std::vector<char> buf;
|
||||
if (std::strstr(i->c_str(), "magnet:") == i->c_str())
|
||||
{
|
||||
std::string btih = url_has_argument(*i, "xt");
|
||||
if (btih.empty()) continue;
|
||||
|
||||
if (btih.compare(0, 9, "urn:btih:") != 0)
|
||||
continue;
|
||||
|
||||
sha1_hash info_hash;
|
||||
if (btih.size() == 40 + 9) from_hex(&btih[9], 40, (char*)&info_hash[0]);
|
||||
else info_hash.assign(base32decode(btih.substr(9)));
|
||||
|
||||
std::string filename = combine_path(save_path, ".resume/"
|
||||
+ to_hex(info_hash.to_string()) + ".resume");
|
||||
|
||||
if (load_file(filename.c_str(), buf, ec) == 0)
|
||||
p.resume_data = &buf;
|
||||
}
|
||||
|
||||
printf("adding URL: %s\n", i->c_str());
|
||||
error_code ec;
|
||||
torrent_handle h = ses.add_torrent(p, ec);
|
||||
|
@ -1985,7 +2005,7 @@ int main(int argc, char* argv[])
|
|||
torrent_handle h = rd->handle;
|
||||
std::vector<char> out;
|
||||
bencode(std::back_inserter(out), *rd->resume_data);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + h.name() + ".resume"), out);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + to_hex(h.info_hash().to_string()) + ".resume"), out);
|
||||
}
|
||||
if (g_log_file) fclose(g_log_file);
|
||||
printf("\nsaving session state\n");
|
||||
|
|
|
@ -1275,6 +1275,10 @@ namespace libtorrent
|
|||
// round-robin index into m_interfaces
|
||||
mutable boost::uint8_t m_interface_index;
|
||||
|
||||
// these are the flags sent in on a call to save_resume_data
|
||||
// we need to save them to check them in write_resume_data
|
||||
boost::uint8_t m_save_resume_flags;
|
||||
|
||||
// set to true when this torrent has been paused but
|
||||
// is waiting to finish all current download requests
|
||||
// before actually closing all connections
|
||||
|
@ -1290,6 +1294,12 @@ namespace libtorrent
|
|||
// rotating sequence number for LSD announces sent out.
|
||||
// used to only use IP broadcast for every 8th lsd announce
|
||||
boost::uint8_t m_lsd_seq:3;
|
||||
|
||||
// this is set to true if the torrent was started without
|
||||
// metadata. It is used to save metadata in the resume file
|
||||
// by default for such torrents. It does not necessarily
|
||||
// have to be a magnet link.
|
||||
bool m_magnet_link:1;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ namespace libtorrent
|
|||
|
||||
void force_recheck() const;
|
||||
|
||||
enum save_resume_flags_t { flush_disk_cache = 1 };
|
||||
enum save_resume_flags_t { flush_disk_cache = 1, save_info_dict = 2 };
|
||||
void save_resume_data(int flags = 0) const;
|
||||
bool need_save_resume_data() const;
|
||||
|
||||
|
|
107
src/torrent.cpp
107
src/torrent.cpp
|
@ -332,11 +332,9 @@ namespace libtorrent
|
|||
, m_total_uploaded(0)
|
||||
, m_total_downloaded(0)
|
||||
, m_started(time_now())
|
||||
, m_torrent_file(p.ti ? p.ti : new torrent_info(info_hash))
|
||||
, m_storage(0)
|
||||
, m_tracker_timer(ses.m_io_service)
|
||||
, m_ses(ses)
|
||||
, m_trackers(m_torrent_file->trackers())
|
||||
, m_trackerid(p.trackerid)
|
||||
, m_save_path(complete(p.save_path))
|
||||
, m_url(p.url)
|
||||
|
@ -358,13 +356,13 @@ namespace libtorrent
|
|||
, m_storage_mode(p.storage_mode)
|
||||
, m_announcing(false)
|
||||
, m_waiting_tracker(false)
|
||||
, m_seed_mode(p.seed_mode && m_torrent_file->is_valid())
|
||||
, m_seed_mode(false)
|
||||
, m_active_time(0)
|
||||
, m_last_working_tracker(-1)
|
||||
, m_finished_time(0)
|
||||
, m_sequential_download(false)
|
||||
, m_got_tracker_response(false)
|
||||
, m_connections_initialized(p.ti && p.ti->is_valid())
|
||||
, m_connections_initialized(false)
|
||||
, m_super_seeding(false)
|
||||
, m_override_resume_data(p.override_resume_data)
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
|
@ -377,8 +375,7 @@ namespace libtorrent
|
|||
, m_max_uploads(~0)
|
||||
, m_deficit_counter(0)
|
||||
, m_num_uploads(0)
|
||||
, m_block_size_shift(root2((p.ti && p.ti->is_valid())
|
||||
? (std::min)(block_size, m_torrent_file->piece_length()) : block_size))
|
||||
, m_block_size_shift(root2(block_size))
|
||||
, m_has_incoming(false)
|
||||
, m_files_checked(false)
|
||||
, m_queued_for_checking(false)
|
||||
|
@ -403,10 +400,99 @@ namespace libtorrent
|
|||
, m_last_upload(0)
|
||||
, m_downloaders(0xffffff)
|
||||
, m_interface_index(0)
|
||||
, m_save_resume_flags(0)
|
||||
, m_graceful_pause_mode(false)
|
||||
, m_need_connect_boost(true)
|
||||
, m_lsd_seq(0)
|
||||
, m_magnet_link(false)
|
||||
{
|
||||
if (!p.ti || !p.ti->is_valid())
|
||||
{
|
||||
// we don't have metadata for this torrent. We'll download
|
||||
// it either through the URL passed in, or through a metadata
|
||||
// extension. Make sure that when we save resume data for this
|
||||
// torrent, we also save the metadata
|
||||
m_magnet_link = true;
|
||||
|
||||
// did the user provide resume data?
|
||||
// maybe the metadata is in there
|
||||
if (p.resume_data)
|
||||
{
|
||||
int pos;
|
||||
error_code ec;
|
||||
lazy_entry tmp;
|
||||
lazy_entry const* info = 0;
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " adding magnet link with resume data\n";
|
||||
#endif
|
||||
if (lazy_bdecode(&(*p.resume_data)[0], &(*p.resume_data)[0]
|
||||
+ p.resume_data->size(), tmp, ec, &pos) == 0
|
||||
&& tmp.type() == lazy_entry::dict_t
|
||||
&& (info = tmp.dict_find_dict("info")))
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " found metadata in resume data\n";
|
||||
#endif
|
||||
// verify the info-hash of the metadata stored in the resume file matches
|
||||
// the torrent we're loading
|
||||
|
||||
std::pair<char const*, int> buf = info->data_section();
|
||||
sha1_hash resume_ih = hasher(buf.first, buf.second).final();
|
||||
|
||||
// if url is set, the info_hash is not actually the info-hash of the
|
||||
// torrent, but the hash of the URL, until we have the full torrent
|
||||
if (resume_ih == info_hash || !p.url.empty())
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " info-hash matched\n";
|
||||
#endif
|
||||
m_torrent_file = (p.ti ? p.ti : new torrent_info(resume_ih));
|
||||
|
||||
if (!m_torrent_file->parse_info_section(*info, ec, 0))
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " failed to load metadata from resume file: "
|
||||
<< ec.message() << "\n";
|
||||
#endif
|
||||
}
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
else
|
||||
{
|
||||
(*m_ses.m_logger) << time_now_string() << " successfully loaded metadata from resume file\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
else
|
||||
{
|
||||
(*m_ses.m_logger) << time_now_string() << " metadata info-hash failed\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
else
|
||||
{
|
||||
(*m_ses.m_logger) << time_now_string() << " no metadata found\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_torrent_file)
|
||||
m_torrent_file = (p.ti ? p.ti : new torrent_info(info_hash));
|
||||
|
||||
m_trackers = m_torrent_file->trackers();
|
||||
if (m_torrent_file->is_valid())
|
||||
{
|
||||
m_seed_mode = p.seed_mode;
|
||||
m_connections_initialized = true;
|
||||
m_block_size_shift = root2((std::min)(block_size, m_torrent_file->piece_length()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p.name) m_name.reset(new std::string(p.name));
|
||||
}
|
||||
|
||||
if (!m_url.empty() && m_uuid.empty()) m_uuid = m_url;
|
||||
|
||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||
|
@ -439,7 +525,6 @@ namespace libtorrent
|
|||
#endif
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (p.name && (!p.ti || !p.ti->is_valid())) m_name.reset(new std::string(p.name));
|
||||
if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url));
|
||||
|
||||
if (p.tracker_url && std::strlen(p.tracker_url) > 0)
|
||||
|
@ -4353,6 +4438,13 @@ namespace libtorrent
|
|||
const sha1_hash& info_hash = torrent_file().info_hash();
|
||||
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
||||
|
||||
if (valid_metadata())
|
||||
{
|
||||
if (m_magnet_link || (m_save_resume_flags & torrent_handle::save_info_dict))
|
||||
ret["info"] = bdecode(&torrent_file().metadata()[0]
|
||||
, &torrent_file().metadata()[0] + torrent_file().metadata_size());
|
||||
}
|
||||
|
||||
// blocks per piece
|
||||
int num_blocks_per_piece =
|
||||
static_cast<int>(torrent_file().piece_length()) / block_size();
|
||||
|
@ -5893,6 +5985,7 @@ namespace libtorrent
|
|||
|
||||
m_need_save_resume_data = false;
|
||||
m_last_saved_resume = time(0);
|
||||
m_save_resume_flags = boost::uint8_t(flags);
|
||||
|
||||
TORRENT_ASSERT(m_storage);
|
||||
if (m_state == torrent_status::queued_for_checking
|
||||
|
|
Loading…
Reference in New Issue