2003-10-30 00:28:09 +01:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2003, 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 <ctime>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
#include <cctype>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push, 1)
|
|
|
|
#endif
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/filesystem/convenience.hpp>
|
2003-12-09 19:09:34 +01:00
|
|
|
#include <boost/optional.hpp>
|
2004-03-23 23:58:18 +01:00
|
|
|
#include <boost/bind.hpp>
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
#include "libtorrent/peer_id.hpp"
|
|
|
|
#include "libtorrent/torrent_info.hpp"
|
2004-01-31 11:46:15 +01:00
|
|
|
#include "libtorrent/tracker_manager.hpp"
|
2003-10-30 00:28:09 +01:00
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/session.hpp"
|
2004-02-29 17:39:52 +01:00
|
|
|
#include "libtorrent/invariant_check.hpp"
|
2003-10-30 00:28:09 +01:00
|
|
|
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER < 1300
|
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
using ::srand;
|
2004-01-02 21:46:24 +01:00
|
|
|
using ::isalnum;
|
2003-10-30 00:28:09 +01:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
2003-12-14 06:56:12 +01:00
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
namespace
|
|
|
|
{
|
2004-03-30 01:25:13 +02:00
|
|
|
#if defined(_MSC_VER) && _MSC_VER < 1300
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
struct transform_void{ typedef T type; };
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct transform_void<void> { typedef int type; };
|
|
|
|
|
|
|
|
template<class Ret>
|
|
|
|
struct void_call_wrapper
|
|
|
|
{
|
|
|
|
template<class F>
|
|
|
|
static Ret call(F f, torrent& t)
|
|
|
|
{
|
|
|
|
return f(t);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct void_call_wrapper<void>
|
|
|
|
{
|
|
|
|
template<class F>
|
|
|
|
static int call(F f, torrent& t)
|
|
|
|
{
|
|
|
|
f(t);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Ret, class F>
|
|
|
|
transform_void<Ret>::type call_member(
|
|
|
|
detail::session_impl* ses
|
|
|
|
, detail::checker_impl* chk
|
|
|
|
, sha1_hash const& hash
|
|
|
|
, F f)
|
|
|
|
{
|
|
|
|
typedef typename transform_void<Ret>::type ret;
|
|
|
|
if (ses == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(ses->m_mutex);
|
|
|
|
torrent* t = ses->find_torrent(hash);
|
|
|
|
if (t != 0) return void_call_wrapper<Ret>::call(f, *t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (chk)
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(chk->m_mutex);
|
|
|
|
|
|
|
|
detail::piece_checker_data* d = chk->find_torrent(hash);
|
|
|
|
if (d != 0) return void_call_wrapper<Ret>::call(f, *d->torrent_ptr);
|
|
|
|
}
|
|
|
|
throw invalid_handle();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
template<class Ret, class F>
|
|
|
|
Ret call_member(
|
|
|
|
detail::session_impl* ses
|
|
|
|
, detail::checker_impl* chk
|
|
|
|
, sha1_hash const& hash
|
|
|
|
, F f)
|
|
|
|
{
|
|
|
|
if (ses == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(ses->m_mutex);
|
|
|
|
torrent* t = ses->find_torrent(hash);
|
|
|
|
if (t != 0) return f(*t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (chk)
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(chk->m_mutex);
|
|
|
|
|
|
|
|
detail::piece_checker_data* d = chk->find_torrent(hash);
|
|
|
|
if (d != 0) return f(*d->torrent_ptr);
|
|
|
|
}
|
|
|
|
throw invalid_handle();
|
|
|
|
}
|
2004-03-30 01:25:13 +02:00
|
|
|
#endif
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
}
|
|
|
|
|
2004-02-29 17:39:52 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
|
|
|
void torrent_handle::check_invariant() const
|
|
|
|
{
|
|
|
|
assert((m_ses == 0 && m_chk == 0) || (m_ses != 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
|
|
|
|
|
2003-12-14 06:56:12 +01:00
|
|
|
void torrent_handle::set_max_uploads(int max_uploads)
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(max_uploads >= 2 || max_uploads == -1);
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&policy::set_max_uploads
|
|
|
|
, boost::bind(&torrent::get_policy, _1)
|
|
|
|
, max_uploads));
|
2003-12-14 06:56:12 +01:00
|
|
|
}
|
2004-01-21 01:59:38 +01:00
|
|
|
|
2004-02-26 01:27:06 +01:00
|
|
|
void torrent_handle::use_interface(const char* net_interface)
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::use_interface, _1, net_interface));
|
2004-02-26 01:27:06 +01:00
|
|
|
}
|
|
|
|
|
2004-01-21 01:59:38 +01:00
|
|
|
void torrent_handle::set_max_connections(int max_connections)
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&policy::set_max_connections
|
|
|
|
, boost::bind(&torrent::get_policy, _1), max_connections));
|
2004-01-21 01:59:38 +01:00
|
|
|
}
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
void torrent_handle::set_upload_limit(int limit)
|
2003-11-28 18:29:27 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
assert(limit >= -1);
|
2003-11-28 18:29:27 +01:00
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::set_upload_limit, _1, limit));
|
2003-11-28 18:29:27 +01:00
|
|
|
}
|
|
|
|
|
2004-07-01 20:51:13 +02:00
|
|
|
void torrent_handle::set_download_limit(int limit)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
assert(limit >= -1);
|
|
|
|
|
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::set_download_limit, _1, limit));
|
|
|
|
}
|
|
|
|
|
2004-07-18 02:39:58 +02:00
|
|
|
bool torrent_handle::move_storage(boost::filesystem::path const& save_path)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
return call_member<bool>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::move_storage, _1, save_path));
|
|
|
|
}
|
|
|
|
|
2004-09-10 02:47:30 +02:00
|
|
|
bool torrent_handle::has_metadata() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
return call_member<bool>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::valid_metadata, _1));
|
|
|
|
}
|
|
|
|
|
2004-09-08 01:16:11 +02:00
|
|
|
bool torrent_handle::is_seed() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
return call_member<bool>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::is_seed, _1));
|
|
|
|
}
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
bool torrent_handle::is_paused() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
return call_member<bool>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::is_paused, _1));
|
2004-03-21 03:03:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent_handle::pause()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::pause, _1));
|
2004-03-21 03:03:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent_handle::resume()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::resume, _1));
|
|
|
|
}
|
2004-03-21 03:03:37 +01:00
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
void torrent_handle::set_tracker_login(std::string const& name, std::string const& password)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2004-03-21 03:03:37 +01:00
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::set_tracker_login, _1, name, password));
|
2004-03-21 03:03:37 +01:00
|
|
|
}
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
|
|
|
|
torrent_status torrent_handle::status() const
|
2004-02-22 23:40:45 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-02-22 23:40:45 +01:00
|
|
|
if (m_ses == 0) throw invalid_handle();
|
2004-03-23 23:58:18 +01:00
|
|
|
|
2004-02-22 23:40:45 +01:00
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
2004-03-23 23:58:18 +01:00
|
|
|
if (t != 0) return t->status();
|
2004-02-22 23:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_chk)
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
2004-03-23 23:58:18 +01:00
|
|
|
|
2004-02-22 23:40:45 +01:00
|
|
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
2004-02-29 13:26:05 +01:00
|
|
|
if (d != 0)
|
|
|
|
{
|
2004-03-23 23:58:18 +01:00
|
|
|
torrent_status st;
|
|
|
|
|
|
|
|
if (d == &m_chk->m_torrents.front())
|
|
|
|
st.state = torrent_status::checking_files;
|
|
|
|
else
|
|
|
|
st.state = torrent_status::queued_for_checking;
|
|
|
|
st.progress = d->progress;
|
|
|
|
st.paused = d->torrent_ptr->is_paused();
|
|
|
|
return st;
|
2004-02-29 13:26:05 +01:00
|
|
|
}
|
2004-02-22 23:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
throw invalid_handle();
|
|
|
|
}
|
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
std::vector<announce_entry> const& torrent_handle::trackers() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
return call_member<std::vector<announce_entry> const&>(m_ses
|
|
|
|
, m_chk, m_info_hash, boost::bind(&torrent::trackers, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent_handle::replace_trackers(std::vector<announce_entry> const& urls)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::replace_trackers, _1, urls));
|
|
|
|
}
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
const torrent_info& torrent_handle::get_torrent_info() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-09-10 02:47:30 +02:00
|
|
|
if (!has_metadata()) throw invalid_handle();
|
2004-03-23 23:58:18 +01:00
|
|
|
return call_member<torrent_info const&>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::torrent_file, _1));
|
|
|
|
}
|
|
|
|
|
2003-12-07 06:53:04 +01:00
|
|
|
bool torrent_handle::is_valid() const
|
2003-11-28 18:29:27 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2003-11-28 18:29:27 +01:00
|
|
|
if (m_ses == 0) return false;
|
|
|
|
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
|
|
|
if (t != 0) return true;
|
|
|
|
}
|
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
if (m_chk)
|
2003-11-28 18:29:27 +01:00
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
|
|
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
|
|
|
if (d != 0) return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2003-10-30 00:28:09 +01:00
|
|
|
}
|
|
|
|
|
2004-02-25 00:55:42 +01:00
|
|
|
entry torrent_handle::write_resume_data() const
|
2004-01-02 21:46:24 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-02 21:46:24 +01:00
|
|
|
std::vector<int> piece_index;
|
2004-09-16 03:14:16 +02:00
|
|
|
if (m_ses == 0) return entry();
|
2004-01-02 21:46:24 +01:00
|
|
|
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
2004-09-16 03:14:16 +02:00
|
|
|
if (t == 0) return entry();
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
if (!t->valid_metadata()) return entry();
|
|
|
|
|
2004-01-02 21:46:24 +01:00
|
|
|
t->filesystem().export_piece_map(piece_index);
|
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
entry ret(entry::dictionary_t);
|
2004-01-02 21:46:24 +01:00
|
|
|
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["file-format"] = "libtorrent resume file";
|
|
|
|
ret["file-version"] = 1;
|
2004-01-03 04:22:53 +01:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
2004-01-02 21:46:24 +01:00
|
|
|
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["slots"] = entry(entry::list_t);
|
2004-03-17 13:14:44 +01:00
|
|
|
entry::list_type& slots = ret["slots"].list();
|
2004-01-07 01:48:02 +01:00
|
|
|
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
|
2004-01-02 21:46:24 +01:00
|
|
|
|
|
|
|
const piece_picker& p = t->picker();
|
|
|
|
|
|
|
|
const std::vector<piece_picker::downloading_piece>& q
|
|
|
|
= p.get_download_queue();
|
|
|
|
|
|
|
|
// blocks per piece
|
|
|
|
int num_blocks_per_piece =
|
2004-03-07 21:50:56 +01:00
|
|
|
static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
|
2004-03-17 13:14:44 +01:00
|
|
|
ret["blocks per piece"] = num_blocks_per_piece;
|
2004-01-02 21:46:24 +01:00
|
|
|
|
2004-04-17 14:29:35 +02:00
|
|
|
// unfinished pieces
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["unfinished"] = entry::list_type();
|
|
|
|
entry::list_type& up = ret["unfinished"].list();
|
2004-01-02 21:46:24 +01:00
|
|
|
|
|
|
|
// info for each unfinished piece
|
|
|
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
|
|
|
= q.begin();
|
|
|
|
i != q.end();
|
|
|
|
++i)
|
|
|
|
{
|
2004-01-24 18:14:03 +01:00
|
|
|
if (i->finished_blocks.count() == 0) continue;
|
|
|
|
|
2004-03-17 13:14:44 +01:00
|
|
|
entry piece_struct(entry::dictionary_t);
|
2004-01-07 01:48:02 +01:00
|
|
|
|
|
|
|
// the unfinished piece's index
|
2004-01-12 21:31:27 +01:00
|
|
|
piece_struct["piece"] = i->index;
|
2004-01-02 21:46:24 +01:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
std::string bitmask;
|
2004-01-24 18:14:03 +01:00
|
|
|
const int num_bitmask_bytes
|
|
|
|
= std::max(num_blocks_per_piece / 8, 1);
|
|
|
|
|
2004-01-04 05:29:13 +01:00
|
|
|
for (int j = 0; j < num_bitmask_bytes; ++j)
|
2004-01-02 21:46:24 +01:00
|
|
|
{
|
2004-01-04 05:29:13 +01:00
|
|
|
unsigned char v = 0;
|
|
|
|
for (int k = 0; k < 8; ++k)
|
|
|
|
v |= i->finished_blocks[j*8+k]?(1 << k):0;
|
2004-01-18 02:58:33 +01:00
|
|
|
bitmask.insert(bitmask.end(), v);
|
2004-01-02 21:46:24 +01:00
|
|
|
}
|
2004-01-12 21:31:27 +01:00
|
|
|
piece_struct["bitmask"] = bitmask;
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2004-01-24 18:14:03 +01:00
|
|
|
assert(t->filesystem().slot_for_piece(i->index) >= 0);
|
|
|
|
unsigned long adler
|
|
|
|
= t->filesystem().piece_crc(
|
|
|
|
t->filesystem().slot_for_piece(i->index)
|
|
|
|
, t->block_size()
|
|
|
|
, i->finished_blocks);
|
|
|
|
|
|
|
|
piece_struct["adler32"] = adler;
|
2004-01-07 01:48:02 +01:00
|
|
|
|
|
|
|
// push the struct onto the unfinished-piece list
|
|
|
|
up.push_back(piece_struct);
|
2004-01-02 21:46:24 +01:00
|
|
|
}
|
2004-01-12 04:05:10 +01:00
|
|
|
|
|
|
|
// write local peers
|
|
|
|
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["peers"] = entry::list_type();
|
|
|
|
entry::list_type& peer_list = ret["peers"].list();
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
for (torrent::const_peer_iterator i = t->begin();
|
2004-01-12 04:05:10 +01:00
|
|
|
i != t->end();
|
|
|
|
++i)
|
|
|
|
{
|
|
|
|
// we cannot save remote connection
|
|
|
|
// since we don't know their listen port
|
2004-06-14 01:30:42 +02:00
|
|
|
// TODO: iterate the peers in the policy
|
|
|
|
// instead, since peers may be remote
|
|
|
|
// but still connectable
|
2004-01-13 04:08:59 +01:00
|
|
|
if (!i->second->is_local()) continue;
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
address ip = i->second->get_socket()->sender();
|
2004-03-17 13:14:44 +01:00
|
|
|
entry peer(entry::dictionary_t);
|
2004-01-12 04:05:10 +01:00
|
|
|
peer["ip"] = ip.as_string();
|
2004-02-26 01:27:06 +01:00
|
|
|
peer["port"] = ip.port;
|
2004-01-12 04:05:10 +01:00
|
|
|
peer_list.push_back(peer);
|
|
|
|
}
|
|
|
|
|
2004-01-17 21:04:19 +01:00
|
|
|
std::vector<size_type> file_sizes
|
|
|
|
= get_filesizes(t->torrent_file(), t->save_path());
|
|
|
|
|
2004-03-05 13:04:47 +01:00
|
|
|
ret["file sizes"] = entry::list_type();
|
2004-01-17 21:04:19 +01:00
|
|
|
std::copy(
|
|
|
|
file_sizes.begin()
|
|
|
|
, file_sizes.end()
|
2004-03-05 13:04:47 +01:00
|
|
|
, std::back_inserter(ret["file sizes"].list()));
|
2004-01-17 21:04:19 +01:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
return ret;
|
2004-01-02 21:46:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-07 06:53:04 +01:00
|
|
|
boost::filesystem::path torrent_handle::save_path() const
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
return call_member<boost::filesystem::path>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::save_path, _1));
|
2003-12-07 06:53:04 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 02:47:30 +02:00
|
|
|
std::vector<char> const& torrent_handle::metadata() const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
return call_member<std::vector<char> const&>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::metadata, _1));
|
|
|
|
}
|
|
|
|
|
2004-01-08 18:03:04 +01:00
|
|
|
void torrent_handle::connect_peer(const address& adr) const
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-08 18:03:04 +01:00
|
|
|
if (m_ses == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
|
|
|
if (t == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
peer_id id;
|
|
|
|
std::fill(id.begin(), id.end(), 0);
|
|
|
|
t->get_policy().peer_from_tracker(adr, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent_handle::force_reannounce() const
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-08 18:03:04 +01:00
|
|
|
if (m_ses == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
|
|
|
if (t == 0) throw invalid_handle();
|
|
|
|
|
|
|
|
t->force_tracker_request();
|
|
|
|
}
|
|
|
|
|
2004-01-12 04:05:10 +01:00
|
|
|
void torrent_handle::set_ratio(float ratio)
|
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-12 04:05:10 +01:00
|
|
|
assert(ratio >= 0.f);
|
|
|
|
|
|
|
|
if (ratio < 1.f && ratio > 0.f)
|
|
|
|
ratio = 1.f;
|
|
|
|
|
2004-03-23 23:58:18 +01:00
|
|
|
call_member<void>(m_ses, m_chk, m_info_hash
|
|
|
|
, boost::bind(&torrent::set_ratio, _1, ratio));
|
2004-01-12 04:05:10 +01:00
|
|
|
}
|
|
|
|
|
2003-12-07 06:53:04 +01:00
|
|
|
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
|
2003-10-30 00:28:09 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
v.clear();
|
2003-11-28 18:29:27 +01:00
|
|
|
if (m_ses == 0) throw invalid_handle();
|
2003-11-06 11:44:19 +01:00
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
const torrent* t = m_ses->find_torrent(m_info_hash);
|
|
|
|
if (t == 0) return;
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
for (torrent::const_peer_iterator i = t->begin();
|
2003-10-30 00:28:09 +01:00
|
|
|
i != t->end();
|
|
|
|
++i)
|
|
|
|
{
|
2004-01-13 04:08:59 +01:00
|
|
|
peer_connection* peer = i->second;
|
2003-12-01 22:27:27 +01:00
|
|
|
|
|
|
|
// peers that hasn't finished the handshake should
|
|
|
|
// not be included in this list
|
|
|
|
if (peer->associated_torrent() == 0) continue;
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
v.push_back(peer_info());
|
|
|
|
peer_info& p = v.back();
|
|
|
|
|
|
|
|
const stat& statistics = peer->statistics();
|
|
|
|
p.down_speed = statistics.download_rate();
|
|
|
|
p.up_speed = statistics.upload_rate();
|
|
|
|
p.id = peer->get_peer_id();
|
|
|
|
p.ip = peer->get_socket()->sender();
|
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
p.total_download = statistics.total_payload_download();
|
|
|
|
p.total_upload = statistics.total_payload_upload();
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2004-03-28 19:45:37 +02:00
|
|
|
if (peer->m_ul_bandwidth_quota.given == std::numeric_limits<int>::max())
|
2004-02-24 20:23:37 +01:00
|
|
|
p.upload_limit = -1;
|
|
|
|
else
|
2004-03-28 19:45:37 +02:00
|
|
|
p.upload_limit = peer->m_ul_bandwidth_quota.given;
|
2004-02-24 20:23:37 +01:00
|
|
|
|
2004-03-28 19:45:37 +02:00
|
|
|
if (peer->m_ul_bandwidth_quota.max == std::numeric_limits<int>::max())
|
2004-02-24 20:23:37 +01:00
|
|
|
p.upload_ceiling = -1;
|
|
|
|
else
|
2004-03-28 19:45:37 +02:00
|
|
|
p.upload_ceiling = peer->m_ul_bandwidth_quota.given;
|
2003-11-09 19:17:09 +01:00
|
|
|
|
2003-12-16 14:33:29 +01:00
|
|
|
p.load_balancing = peer->total_free_upload();
|
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
p.download_queue_length = (int)peer->download_queue().size();
|
|
|
|
p.upload_queue_length = (int)peer->upload_queue().size();
|
2004-01-05 00:51:54 +01:00
|
|
|
|
2003-12-09 19:09:34 +01:00
|
|
|
boost::optional<piece_block_progress> ret = peer->downloading_piece();
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
p.downloading_piece_index = ret->piece_index;
|
|
|
|
p.downloading_block_index = ret->block_index;
|
|
|
|
p.downloading_progress = ret->bytes_downloaded;
|
|
|
|
p.downloading_total = ret->full_block_bytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p.downloading_piece_index = -1;
|
|
|
|
p.downloading_block_index = -1;
|
|
|
|
p.downloading_progress = 0;
|
|
|
|
p.downloading_total = 0;
|
|
|
|
}
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
p.flags = 0;
|
|
|
|
if (peer->is_interesting()) p.flags |= peer_info::interesting;
|
2003-12-01 06:01:40 +01:00
|
|
|
if (peer->is_choked()) p.flags |= peer_info::choked;
|
2003-10-30 00:28:09 +01:00
|
|
|
if (peer->is_peer_interested()) p.flags |= peer_info::remote_interested;
|
|
|
|
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;
|
2004-01-04 05:29:13 +01:00
|
|
|
if (peer->support_extensions()) p.flags |= peer_info::supports_extensions;
|
2004-01-09 11:50:22 +01:00
|
|
|
if (peer->is_local()) p.flags |= peer_info::local_connection;
|
2003-10-30 00:28:09 +01:00
|
|
|
|
|
|
|
p.pieces = peer->get_bitfield();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-07 06:53:04 +01:00
|
|
|
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const
|
2003-10-30 00:28:09 +01:00
|
|
|
{
|
2004-02-29 17:39:52 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2003-11-28 18:29:27 +01:00
|
|
|
if (m_ses == 0) throw invalid_handle();
|
2003-11-02 22:06:50 +01:00
|
|
|
|
|
|
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
|
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
queue.clear();
|
2003-11-02 22:06:50 +01:00
|
|
|
if (t == 0) return;
|
2004-06-14 01:30:42 +02:00
|
|
|
if (!t->valid_metadata()) return;
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2003-11-02 22:06:50 +01:00
|
|
|
const piece_picker& p = t->picker();
|
|
|
|
|
|
|
|
const std::vector<piece_picker::downloading_piece>& q
|
|
|
|
= p.get_download_queue();
|
|
|
|
|
|
|
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
|
|
|
= q.begin();
|
|
|
|
i != q.end();
|
|
|
|
++i)
|
|
|
|
{
|
|
|
|
partial_piece_info pi;
|
|
|
|
pi.finished_blocks = i->finished_blocks;
|
|
|
|
pi.requested_blocks = i->requested_blocks;
|
|
|
|
for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j)
|
|
|
|
{
|
|
|
|
pi.peer[j] = i->info[j].peer;
|
|
|
|
pi.num_downloads[j] = i->info[j].num_downloads;
|
|
|
|
}
|
|
|
|
pi.piece_index = i->index;
|
|
|
|
pi.blocks_in_piece = p.blocks_in_piece(i->index);
|
|
|
|
queue.push_back(pi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
}
|