*** empty log message ***
This commit is contained in:
parent
d7f92afea3
commit
6466b46573
|
@ -455,7 +455,6 @@ struct torrent_handle
|
||||||
{
|
{
|
||||||
torrent_handle();
|
torrent_handle();
|
||||||
|
|
||||||
float progress() const;
|
|
||||||
void get_peer_info(std::vector<peer_info>& v);
|
void get_peer_info(std::vector<peer_info>& v);
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
|
@ -466,37 +465,65 @@ struct torrent_handle
|
||||||
downloading,
|
downloading,
|
||||||
seeding
|
seeding
|
||||||
};
|
};
|
||||||
state_t state() const;
|
|
||||||
|
torrent_status status() const;
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<!-- TODO: temporary comment -->
|
<p>
|
||||||
<p><tt>progress()</tt> and <tt>state()</tt>is not implemented yet</tt>.</p>
|
<tt>abort()</tt> will close all peer connections associated with this torrent and tell
|
||||||
|
the tracker that we've stopped participating in the swarm. This handle will become invalid
|
||||||
|
shortly after this call has been made.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>progress()</tt> will return a value in the range [0, 1], that represents the progress
|
<tt>status()</tt> will return a structure with information about the status of this
|
||||||
of the torrent's current task. It may be checking files, connecting to tracker, or downloading
|
torrent. It contains the following fields:
|
||||||
etc. You can get the torrent's current task bu calling <tt>state()</tt>, it will return one of
|
</p>
|
||||||
the following:
|
|
||||||
|
<pre>
|
||||||
|
struct torrent_status
|
||||||
|
{
|
||||||
|
enum state_t
|
||||||
|
{
|
||||||
|
invalid_handle,
|
||||||
|
queued_for_checking,
|
||||||
|
checking_files,
|
||||||
|
connecting_to_tracker,
|
||||||
|
downloading,
|
||||||
|
seeding
|
||||||
|
};
|
||||||
|
|
||||||
|
state_t state;
|
||||||
|
float progress;
|
||||||
|
std::size_t total_download;
|
||||||
|
std::size_t total_upload;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>progress</tt> is a value in the range [0, 1], that represents the progress of the
|
||||||
|
torrent's current task. It may be checking files or downloading. The torrent's
|
||||||
|
current task is in the <tt>state</tt> member, it will be one of the following:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<tt>queued_for_cecking</tt>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
The torrent is in the queue for being checked. But there currently is another
|
||||||
|
torrent that are being checked. This torrent will wait for its turn.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<tt>checking_files</tt>
|
<tt>checking_files</tt>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
The torrent has not started its download yet, and is currently checking existing
|
The torrent has not started its download yet, and is currently checking existing
|
||||||
files or is queued for having its files checked.
|
files.
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<tt>connecting_to_tracker</tt>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
The torrent is waiting for tracker reply or waiting to retry a tracker connection.
|
|
||||||
If it's waiting to retry the progress meter will hint about when it will retry.
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -520,9 +547,8 @@ the following:
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>abort()</tt> will close all peer connections associated with this torrent and tell
|
<tt>total_download</tt> and <tt>total_upload</tt> is the number of bytes downloaded and
|
||||||
the tracker that we've stopped participating in the swarm. This handle will become invalid
|
uploaded to all peers, accumulated.
|
||||||
shortly after this call has been made.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -56,6 +56,20 @@ bool sleep_and_input(char* c)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string add_suffix(float val)
|
||||||
|
{
|
||||||
|
const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
|
||||||
|
const int num_prefix = sizeof(prefix) / sizeof(const char*);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < num_prefix; ++i)
|
||||||
|
{
|
||||||
|
if (val < 1024.f)
|
||||||
|
return boost::lexical_cast<std::string>(val) + prefix[i];
|
||||||
|
val /= 1024.f;
|
||||||
|
}
|
||||||
|
return boost::lexical_cast<std::string>(val) + prefix[i];
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
@ -97,10 +111,6 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<torrent_handle::state_t, float> prev_status
|
|
||||||
= std::make_pair(torrent_handle::invalid_handle, 0.f);
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<peer_info> peers;
|
std::vector<peer_info> peers;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -111,63 +121,55 @@ int main(int argc, char* argv[])
|
||||||
if (c == 'q') break;
|
if (c == 'q') break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// just print info from the first torrent
|
for (std::vector<torrent_handle>::iterator i = handles.begin();
|
||||||
torrent_handle h = handles.front();
|
i != handles.end();
|
||||||
|
|
||||||
std::pair<torrent_handle::state_t, float> s
|
|
||||||
= h.status();
|
|
||||||
|
|
||||||
if (s.first == prev_status.first
|
|
||||||
&& s.second == prev_status.second)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch(s.first)
|
|
||||||
{
|
|
||||||
case torrent_handle::checking_files:
|
|
||||||
std::cout << "checking files: ";
|
|
||||||
break;
|
|
||||||
case torrent_handle::downloading:
|
|
||||||
std::cout << "downloading: ";
|
|
||||||
break;
|
|
||||||
case torrent_handle::seeding:
|
|
||||||
std::cout << "seeding: ";
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::cout.width(3);
|
|
||||||
std::cout.precision(3);
|
|
||||||
std::cout.fill('0');
|
|
||||||
std::cout << s.second*100 << "% ";
|
|
||||||
|
|
||||||
// calculate download and upload speeds
|
|
||||||
h.get_peer_info(peers);
|
|
||||||
float down = 0.f;
|
|
||||||
float up = 0.f;
|
|
||||||
unsigned int total_down = 0;
|
|
||||||
unsigned int total_up = 0;
|
|
||||||
int num_peers = peers.size();
|
|
||||||
|
|
||||||
for (std::vector<peer_info>::iterator i = peers.begin();
|
|
||||||
i != peers.end();
|
|
||||||
++i)
|
++i)
|
||||||
{
|
{
|
||||||
down += i->down_speed;
|
torrent_status s = i->status();
|
||||||
up += i->up_speed;
|
|
||||||
total_down += i->total_download;
|
switch(s.state)
|
||||||
total_up += i->total_upload;
|
{
|
||||||
|
case torrent_status::queued_for_checking:
|
||||||
|
std::cout << "queued for checking: ";
|
||||||
|
break;
|
||||||
|
case torrent_status::checking_files:
|
||||||
|
std::cout << "checking files: ";
|
||||||
|
break;
|
||||||
|
case torrent_status::downloading:
|
||||||
|
std::cout << "downloading: ";
|
||||||
|
break;
|
||||||
|
case torrent_status::seeding:
|
||||||
|
std::cout << "seeding: ";
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::cout << s.progress*100 << "% ";
|
||||||
|
|
||||||
|
// calculate download and upload speeds
|
||||||
|
i->get_peer_info(peers);
|
||||||
|
float down = 0.f;
|
||||||
|
float up = 0.f;
|
||||||
|
unsigned int total_down = 0;
|
||||||
|
unsigned int total_up = 0;
|
||||||
|
int num_peers = peers.size();
|
||||||
|
|
||||||
|
for (std::vector<peer_info>::iterator i = peers.begin();
|
||||||
|
i != peers.end();
|
||||||
|
++i)
|
||||||
|
{
|
||||||
|
down += i->down_speed;
|
||||||
|
up += i->up_speed;
|
||||||
|
total_down += i->total_download;
|
||||||
|
total_up += i->total_upload;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "p:" << num_peers;
|
||||||
|
|
||||||
|
std::cout << " d:("
|
||||||
|
<< add_suffix(total_down) << ") " << add_suffix(down) << "/s up:("
|
||||||
|
<< add_suffix(total_up) << ") " << add_suffix(up) << "/s\n";
|
||||||
}
|
}
|
||||||
|
std::cout << "----\n";
|
||||||
std::cout.width(2);
|
|
||||||
std::cout.precision(2);
|
|
||||||
|
|
||||||
std::cout << "p:" << num_peers;
|
|
||||||
|
|
||||||
std::cout.width(6);
|
|
||||||
std::cout.precision(6);
|
|
||||||
|
|
||||||
std::cout << " d:("
|
|
||||||
<< total_down/1024.f << " kB) " << down/1024.f << " kB/s up:("
|
|
||||||
<< total_up/1024.f << " kB) " << up/1024.f << " kB/s \r";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
|
|
@ -199,6 +199,9 @@ namespace libtorrent
|
||||||
data_type m_type;
|
data_type m_type;
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
// workaround for msvc-bug.
|
||||||
|
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
char data[detail::max4<sizeof(list_type)
|
char data[detail::max4<sizeof(list_type)
|
||||||
|
|
|
@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
@ -86,21 +87,13 @@ namespace libtorrent
|
||||||
// thread that initialize pieces
|
// thread that initialize pieces
|
||||||
struct piece_checker_data
|
struct piece_checker_data
|
||||||
{
|
{
|
||||||
piece_checker_data(): abort(false) {}
|
piece_checker_data(): progress(0.f), abort(false) {}
|
||||||
|
|
||||||
boost::shared_ptr<torrent> torrent_ptr;
|
boost::shared_ptr<torrent> torrent_ptr;
|
||||||
std::string save_path;
|
std::string save_path;
|
||||||
|
|
||||||
// when the files has been checked
|
|
||||||
// the torrent is added to the session
|
|
||||||
session_impl* ses;
|
|
||||||
|
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
|
|
||||||
// must be locked to access the data
|
|
||||||
// below in this struct
|
|
||||||
boost::mutex mutex;
|
|
||||||
|
|
||||||
// is filled in by storage::initialize_pieces()
|
// is filled in by storage::initialize_pieces()
|
||||||
// and represents the progress. It should be a
|
// and represents the progress. It should be a
|
||||||
// value in the range [0, 1]
|
// value in the range [0, 1]
|
||||||
|
@ -112,42 +105,51 @@ namespace libtorrent
|
||||||
bool abort;
|
bool abort;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct piece_check_thread
|
struct checker_impl: boost::noncopyable
|
||||||
{
|
{
|
||||||
piece_check_thread(const boost::shared_ptr<piece_checker_data>& p)
|
checker_impl(session_impl* s): m_ses(s), m_abort(false) {}
|
||||||
: m_data(p)
|
|
||||||
{}
|
|
||||||
void operator()();
|
void operator()();
|
||||||
boost::shared_ptr<piece_checker_data> m_data;
|
piece_checker_data* find_torrent(const sha1_hash& info_hash);
|
||||||
};
|
|
||||||
|
|
||||||
|
// when the files has been checked
|
||||||
|
// the torrent is added to the session
|
||||||
|
session_impl* m_ses;
|
||||||
|
|
||||||
|
boost::mutex m_mutex;
|
||||||
|
boost::condition m_cond;
|
||||||
|
|
||||||
|
// a list of all torrents that are currently checking
|
||||||
|
// their files (in separate threads)
|
||||||
|
std::deque<piece_checker_data> m_torrents;
|
||||||
|
|
||||||
|
bool m_abort;
|
||||||
|
};
|
||||||
|
|
||||||
// this is the link between the main thread and the
|
// this is the link between the main thread and the
|
||||||
// thread started to run the main downloader loop
|
// thread started to run the main downloader loop
|
||||||
struct session_impl
|
struct session_impl: boost::noncopyable
|
||||||
{
|
{
|
||||||
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> > connection_map;
|
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> > connection_map;
|
||||||
|
|
||||||
session_impl(const std::string& fingerprint);
|
session_impl(int listen_port, const std::string& fingerprint);
|
||||||
|
void operator()();
|
||||||
|
|
||||||
// must be locked to access the data
|
// must be locked to access the data
|
||||||
// in this struct
|
// in this struct
|
||||||
boost::mutex m_mutex;
|
boost::mutex m_mutex;
|
||||||
|
torrent* find_torrent(const sha1_hash& info_hash);
|
||||||
|
const peer_id& get_peer_id() const { return m_peer_id; }
|
||||||
|
|
||||||
tracker_manager m_tracker_manager;
|
tracker_manager m_tracker_manager;
|
||||||
std::map<sha1_hash, boost::shared_ptr<torrent> > m_torrents;
|
std::map<sha1_hash, boost::shared_ptr<torrent> > m_torrents;
|
||||||
connection_map m_connections;
|
connection_map m_connections;
|
||||||
|
|
||||||
// a list of all torrents that are currently checking
|
|
||||||
// their files (in separate threads)
|
|
||||||
std::map<sha1_hash,
|
|
||||||
boost::shared_ptr<detail::piece_checker_data>
|
|
||||||
> m_checkers;
|
|
||||||
boost::thread_group m_checker_threads;
|
|
||||||
|
|
||||||
// the peer id that is generated at the start of each torrent
|
// the peer id that is generated at the start of each torrent
|
||||||
peer_id m_peer_id;
|
peer_id m_peer_id;
|
||||||
|
|
||||||
|
// the port we are listening on for connections
|
||||||
|
int m_listen_port;
|
||||||
|
|
||||||
// this is where all active sockets are stored.
|
// this is where all active sockets are stored.
|
||||||
// the selector can sleep while there's no activity on
|
// the selector can sleep while there's no activity on
|
||||||
// them
|
// them
|
||||||
|
@ -158,13 +160,6 @@ namespace libtorrent
|
||||||
|
|
||||||
bool m_abort;
|
bool m_abort;
|
||||||
|
|
||||||
void run(int listen_port);
|
|
||||||
|
|
||||||
torrent* find_active_torrent(const sha1_hash& info_hash);
|
|
||||||
detail::piece_checker_data* find_checking_torrent(const sha1_hash& info_hash);
|
|
||||||
|
|
||||||
const peer_id& get_peer_id() const { return m_peer_id; }
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
boost::shared_ptr<logger> create_log(std::string name)
|
boost::shared_ptr<logger> create_log(std::string name)
|
||||||
{
|
{
|
||||||
|
@ -177,34 +172,6 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct main_loop_thread
|
|
||||||
{
|
|
||||||
main_loop_thread(int listen_port, session_impl* s)
|
|
||||||
: m_ses(s), m_listen_port(listen_port)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void operator()()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_ses->run(m_listen_port);
|
|
||||||
}
|
|
||||||
catch(std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << typeid(e).name() << "\n";
|
|
||||||
std::cerr << e.what() << "\n";
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session_impl* m_ses;
|
|
||||||
int m_listen_port;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct http_settings;
|
struct http_settings;
|
||||||
|
@ -216,8 +183,11 @@ namespace libtorrent
|
||||||
public:
|
public:
|
||||||
|
|
||||||
session(int listen_port, const std::string& fingerprint = std::string())
|
session(int listen_port, const std::string& fingerprint = std::string())
|
||||||
: m_impl(fingerprint)
|
: m_impl(listen_port, fingerprint)
|
||||||
, m_thread(detail::main_loop_thread(listen_port, &m_impl)) {}
|
, m_checker_impl(&m_impl)
|
||||||
|
, m_thread(boost::ref(m_impl))
|
||||||
|
, m_checker_thread(boost::ref(m_checker_impl))
|
||||||
|
{}
|
||||||
|
|
||||||
~session();
|
~session();
|
||||||
|
|
||||||
|
@ -228,11 +198,20 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// data shared between the threads
|
// data shared between the main thread
|
||||||
|
// and the working thread
|
||||||
detail::session_impl m_impl;
|
detail::session_impl m_impl;
|
||||||
|
|
||||||
|
// data shared between the main thread
|
||||||
|
// and the checker thread
|
||||||
|
detail::checker_impl m_checker_impl;
|
||||||
|
|
||||||
// the main working thread
|
// the main working thread
|
||||||
boost::thread m_thread;
|
boost::thread m_thread;
|
||||||
|
|
||||||
|
// the thread that calls initialize_pieces()
|
||||||
|
// on all torrents before they start downloading
|
||||||
|
boost::thread m_checker_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
|
@ -145,7 +146,8 @@ namespace libtorrent
|
||||||
|
|
||||||
void initialize_pieces(torrent* t,
|
void initialize_pieces(torrent* t,
|
||||||
const boost::filesystem::path& path,
|
const boost::filesystem::path& path,
|
||||||
boost::shared_ptr<detail::piece_checker_data> data);
|
detail::piece_checker_data* data,
|
||||||
|
boost::mutex* mutex);
|
||||||
|
|
||||||
int bytes_left() const { return m_bytes_left; }
|
int bytes_left() const { return m_bytes_left; }
|
||||||
|
|
||||||
|
|
|
@ -100,10 +100,11 @@ namespace libtorrent
|
||||||
|
|
||||||
void print(std::ostream& os) const;
|
void print(std::ostream& os) const;
|
||||||
|
|
||||||
void allocate_files(boost::shared_ptr<detail::piece_checker_data> data,
|
void allocate_files(detail::piece_checker_data* data,
|
||||||
|
boost::mutex* mutex,
|
||||||
const std::string& save_path)
|
const std::string& save_path)
|
||||||
{
|
{
|
||||||
m_storage.initialize_pieces(this, save_path, data);
|
m_storage.initialize_pieces(this, save_path, data, mutex);
|
||||||
m_picker.files_checked(m_storage.pieces());
|
m_picker.files_checked(m_storage.pieces());
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
m_picker.integrity_check(this);
|
m_picker.integrity_check(this);
|
||||||
|
@ -117,7 +118,7 @@ namespace libtorrent
|
||||||
int bytes_uploaded() const { return m_bytes_uploaded; }
|
int bytes_uploaded() const { return m_bytes_uploaded; }
|
||||||
int bytes_left() const { return m_storage.bytes_left(); }
|
int bytes_left() const { return m_storage.bytes_left(); }
|
||||||
|
|
||||||
std::pair<torrent_handle::state_t, float> status() const;
|
torrent_status status() const;
|
||||||
|
|
||||||
void connect_to_peer(const address& a, const peer_id& id);
|
void connect_to_peer(const address& a, const peer_id& id);
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,27 @@ namespace libtorrent
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
struct session_impl;
|
struct session_impl;
|
||||||
|
struct checker_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct torrent_status
|
||||||
|
{
|
||||||
|
enum state_t
|
||||||
|
{
|
||||||
|
invalid_handle,
|
||||||
|
queued_for_checking,
|
||||||
|
checking_files,
|
||||||
|
connecting_to_tracker,
|
||||||
|
downloading,
|
||||||
|
seeding
|
||||||
|
};
|
||||||
|
|
||||||
|
state_t state;
|
||||||
|
float progress;
|
||||||
|
std::size_t total_download;
|
||||||
|
std::size_t total_upload;
|
||||||
|
};
|
||||||
|
|
||||||
struct torrent_handle
|
struct torrent_handle
|
||||||
{
|
{
|
||||||
friend class session;
|
friend class session;
|
||||||
|
@ -54,27 +73,23 @@ namespace libtorrent
|
||||||
|
|
||||||
void get_peer_info(std::vector<peer_info>& v);
|
void get_peer_info(std::vector<peer_info>& v);
|
||||||
void abort();
|
void abort();
|
||||||
enum state_t
|
|
||||||
{
|
torrent_status status() const;
|
||||||
invalid_handle,
|
|
||||||
checking_files,
|
|
||||||
connecting_to_tracker,
|
|
||||||
downloading,
|
|
||||||
seeding
|
|
||||||
};
|
|
||||||
std::pair<state_t, float> status() const;
|
|
||||||
|
|
||||||
// TODO: add a 'time to next announce' query.
|
// TODO: add a 'time to next announce' query.
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
torrent_handle(detail::session_impl* s, const sha1_hash& h)
|
torrent_handle(detail::session_impl* s,
|
||||||
|
detail::checker_impl* c,
|
||||||
|
const sha1_hash& h)
|
||||||
: m_ses(s)
|
: m_ses(s)
|
||||||
|
, m_chk(c)
|
||||||
, m_info_hash(h)
|
, m_info_hash(h)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
detail::session_impl* m_ses;
|
detail::session_impl* m_ses;
|
||||||
|
detail::checker_impl* m_chk;
|
||||||
sha1_hash m_info_hash; // should be replaced with a torrent*?
|
sha1_hash m_info_hash; // should be replaced with a torrent*?
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -638,7 +638,7 @@ void libtorrent::peer_connection::receive_data()
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
std::copy(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (char*)info_hash.begin());
|
std::copy(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (char*)info_hash.begin());
|
||||||
|
|
||||||
m_torrent = m_ses->find_active_torrent(info_hash);
|
m_torrent = m_ses->find_torrent(info_hash);
|
||||||
if (m_torrent == 0)
|
if (m_torrent == 0)
|
||||||
{
|
{
|
||||||
// we couldn't find the torrent!
|
// we couldn't find the torrent!
|
||||||
|
|
242
src/session.cpp
242
src/session.cpp
|
@ -77,33 +77,98 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
session_impl::session_impl(const std::string& cl_fprint)
|
void checker_impl::operator()()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
piece_checker_data* t;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
|
// if the job queue is empty and
|
||||||
|
// we shouldn't abort
|
||||||
|
// wait for a signal
|
||||||
|
if (m_torrents.empty() && !m_abort)
|
||||||
|
m_cond.wait(l);
|
||||||
|
|
||||||
|
if (m_abort) return;
|
||||||
|
|
||||||
|
assert(!m_torrents.empty());
|
||||||
|
|
||||||
|
t = &m_torrents.front();
|
||||||
|
if (t->abort)
|
||||||
|
{
|
||||||
|
m_torrents.pop_front();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
t->torrent_ptr->allocate_files(t, &m_mutex, t->save_path);
|
||||||
|
// lock the session to add the new torrent
|
||||||
|
|
||||||
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
if (!t->abort)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "adding torrent to session!\n";
|
||||||
|
#endif
|
||||||
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||||
|
|
||||||
|
m_ses->m_torrents.insert(
|
||||||
|
std::make_pair(t->info_hash, t->torrent_ptr)).first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "error while checking files\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove ourself from the 'checking'-list
|
||||||
|
// (we're no longer in the checking state)
|
||||||
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
m_torrents.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::piece_checker_data* checker_impl::find_torrent(const sha1_hash& info_hash)
|
||||||
|
{
|
||||||
|
for (std::deque<piece_checker_data>::iterator i
|
||||||
|
= m_torrents.begin();
|
||||||
|
i != m_torrents.end();
|
||||||
|
++i)
|
||||||
|
{
|
||||||
|
if (i->info_hash == info_hash) return &(*i);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_impl::session_impl(int listen_port,
|
||||||
|
const std::string& cl_fprint)
|
||||||
: m_abort(false)
|
: m_abort(false)
|
||||||
, m_tracker_manager(m_settings)
|
, m_tracker_manager(m_settings)
|
||||||
|
, m_listen_port(listen_port)
|
||||||
{
|
{
|
||||||
|
|
||||||
// ---- generate a peer id ----
|
// ---- generate a peer id ----
|
||||||
|
|
||||||
std::srand(std::time(0));
|
std::srand(std::time(0));
|
||||||
|
|
||||||
// libtorrent's fingerprint
|
const int len1 = std::min(cl_fprint.length(), (std::size_t)7);
|
||||||
unsigned char fingerprint[] = "lt.";
|
const int len2 = 12 - len1;
|
||||||
|
|
||||||
const int len2 = std::min(cl_fprint.length(), (std::size_t)7);
|
|
||||||
const int len1 = (len2 == 0?2:3);
|
|
||||||
const int len3 = 12 - len1 - len2;
|
|
||||||
|
|
||||||
std::copy(fingerprint, fingerprint+len1, m_peer_id.begin());
|
|
||||||
|
|
||||||
// the client's fingerprint
|
// the client's fingerprint
|
||||||
std::copy(cl_fprint.begin(), cl_fprint.begin()+len2, m_peer_id.begin()+len1);
|
std::copy(cl_fprint.begin(), cl_fprint.begin()+len2, m_peer_id.begin());
|
||||||
|
|
||||||
// the zeros
|
// the zeros
|
||||||
std::fill(m_peer_id.begin()+len1+len2, m_peer_id.begin()+len1+len2+len3, 0);
|
std::fill(m_peer_id.begin()+len1, m_peer_id.begin()+len1+len2, 0);
|
||||||
assert(len1 + len2 + len3 == 12);
|
assert(len1 + len2 == 12);
|
||||||
|
|
||||||
// the random number
|
// the random number
|
||||||
for (unsigned char* i = m_peer_id.begin()+len1+len2+len3;
|
for (unsigned char* i = m_peer_id.begin()+len1+len2;
|
||||||
i != m_peer_id.end();
|
i != m_peer_id.end();
|
||||||
++i)
|
++i)
|
||||||
{
|
{
|
||||||
|
@ -112,14 +177,14 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void session_impl::run(int listen_port)
|
void session_impl::operator()()
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_logger = create_log("main session");
|
m_logger = create_log("main session");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::shared_ptr<socket> listener(new socket(socket::tcp, false));
|
boost::shared_ptr<socket> listener(new socket(socket::tcp, false));
|
||||||
int max_port = listen_port + 9;
|
int max_port = m_listen_port + 9;
|
||||||
|
|
||||||
|
|
||||||
// create listener socket
|
// create listener socket
|
||||||
|
@ -128,19 +193,19 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
listener->listen(listen_port, 5);
|
listener->listen(m_listen_port, 5);
|
||||||
}
|
}
|
||||||
catch(network_error&)
|
catch(network_error&)
|
||||||
{
|
{
|
||||||
if (listen_port > max_port) throw;
|
if (m_listen_port > max_port) throw;
|
||||||
listen_port++;
|
m_listen_port++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
(*m_logger) << "listening on port: " << listen_port << "\n";
|
(*m_logger) << "listening on port: " << m_listen_port << "\n";
|
||||||
#endif
|
#endif
|
||||||
m_selector.monitor_readability(listener);
|
m_selector.monitor_readability(listener);
|
||||||
m_selector.monitor_errors(listener);
|
m_selector.monitor_errors(listener);
|
||||||
|
@ -163,6 +228,9 @@ namespace libtorrent
|
||||||
std::vector<boost::shared_ptr<socket> > writable_clients;
|
std::vector<boost::shared_ptr<socket> > writable_clients;
|
||||||
std::vector<boost::shared_ptr<socket> > error_clients;
|
std::vector<boost::shared_ptr<socket> > error_clients;
|
||||||
boost::posix_time::ptime timer = boost::posix_time::second_clock::local_time();
|
boost::posix_time::ptime timer = boost::posix_time::second_clock::local_time();
|
||||||
|
#ifdef TORRENT_DEBUG_SOCKETS
|
||||||
|
int num_loops = 0;
|
||||||
|
#endif
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// if nothing happens within 500000 microseconds (0.5 seconds)
|
// if nothing happens within 500000 microseconds (0.5 seconds)
|
||||||
|
@ -171,6 +239,9 @@ namespace libtorrent
|
||||||
m_selector.wait(500000, readable_clients, writable_clients, error_clients);
|
m_selector.wait(500000, readable_clients, writable_clients, error_clients);
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
#ifdef TORRENT_DEBUG_SOCKETS
|
||||||
|
num_loops++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// +1 for the listen socket
|
// +1 for the listen socket
|
||||||
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
|
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
|
||||||
|
@ -184,7 +255,7 @@ namespace libtorrent
|
||||||
++i)
|
++i)
|
||||||
{
|
{
|
||||||
i->second->abort();
|
i->second->abort();
|
||||||
m_tracker_manager.queue_request(i->second->generate_tracker_request(listen_port));
|
m_tracker_manager.queue_request(i->second->generate_tracker_request(m_listen_port));
|
||||||
}
|
}
|
||||||
m_connections.clear();
|
m_connections.clear();
|
||||||
m_torrents.clear();
|
m_torrents.clear();
|
||||||
|
@ -215,7 +286,7 @@ namespace libtorrent
|
||||||
(*m_logger) << s->sender().as_string() << " <== INCOMING CONNECTION\n";
|
(*m_logger) << s->sender().as_string() << " <== INCOMING CONNECTION\n";
|
||||||
#endif
|
#endif
|
||||||
// TODO: the send buffer size should be controllable from the outside
|
// TODO: the send buffer size should be controllable from the outside
|
||||||
s->set_send_bufsize(2048);
|
// s->set_send_bufsize(2048);
|
||||||
|
|
||||||
// TODO: add some possibility to filter IP:s
|
// TODO: add some possibility to filter IP:s
|
||||||
boost::shared_ptr<peer_connection> c(new peer_connection(this, s));
|
boost::shared_ptr<peer_connection> c(new peer_connection(this, s));
|
||||||
|
@ -351,6 +422,12 @@ namespace libtorrent
|
||||||
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
|
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
|
||||||
// ************************
|
// ************************
|
||||||
|
|
||||||
|
#ifdef TORRENT_DEBUG_SOCKETS
|
||||||
|
std::cout << "\nloops: " << num_loops << "\n";
|
||||||
|
assert(loops < 1300);
|
||||||
|
num_loops = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// do the second_tick() on each connection
|
// do the second_tick() on each connection
|
||||||
// this will update their statistics (download and upload speeds)
|
// this will update their statistics (download and upload speeds)
|
||||||
|
@ -361,12 +438,14 @@ namespace libtorrent
|
||||||
|
|
||||||
// check each torrent for abortion or
|
// check each torrent for abortion or
|
||||||
// tracker updates
|
// tracker updates
|
||||||
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i = m_torrents.begin();
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
||||||
|
= m_torrents.begin();
|
||||||
i != m_torrents.end();)
|
i != m_torrents.end();)
|
||||||
{
|
{
|
||||||
if (i->second->is_aborted())
|
if (i->second->is_aborted())
|
||||||
{
|
{
|
||||||
m_tracker_manager.queue_request(i->second->generate_tracker_request(listen_port));
|
m_tracker_manager.queue_request(
|
||||||
|
i->second->generate_tracker_request(m_listen_port));
|
||||||
i->second->close_all_connections();
|
i->second->close_all_connections();
|
||||||
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j = i;
|
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j = i;
|
||||||
++i;
|
++i;
|
||||||
|
@ -376,7 +455,7 @@ namespace libtorrent
|
||||||
else if (i->second->should_request())
|
else if (i->second->should_request())
|
||||||
{
|
{
|
||||||
m_tracker_manager.queue_request(
|
m_tracker_manager.queue_request(
|
||||||
i->second->generate_tracker_request(listen_port),
|
i->second->generate_tracker_request(m_listen_port),
|
||||||
boost::get_pointer(i->second));
|
boost::get_pointer(i->second));
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
|
@ -409,7 +488,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// the return value from this function is valid only as long as the
|
// the return value from this function is valid only as long as the
|
||||||
// session is locked!
|
// session is locked!
|
||||||
torrent* session_impl::find_active_torrent(const sha1_hash& info_hash)
|
torrent* session_impl::find_torrent(const sha1_hash& info_hash)
|
||||||
{
|
{
|
||||||
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
||||||
= m_torrents.find(info_hash);
|
= m_torrents.find(info_hash);
|
||||||
|
@ -417,67 +496,31 @@ namespace libtorrent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
piece_checker_data* session_impl::find_checking_torrent(const sha1_hash& info_hash)
|
|
||||||
{
|
|
||||||
std::map<sha1_hash, boost::shared_ptr<detail::piece_checker_data> >::iterator i
|
|
||||||
= m_checkers.find(info_hash);
|
|
||||||
|
|
||||||
if (i != m_checkers.end())
|
|
||||||
return boost::get_pointer(i->second);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void piece_check_thread::operator()()
|
|
||||||
{
|
|
||||||
// TODO: implement a way to abort a file check and
|
|
||||||
// to get feedback on how much of the data that has
|
|
||||||
// been checked and how much of the file we have
|
|
||||||
// (which should be about the same thing with the
|
|
||||||
// new allocation model)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_data->torrent_ptr->allocate_files(m_data, m_data->save_path);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
std::cout << "error while checking files\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock the session to add the new torrent
|
|
||||||
session_impl* ses = m_data->ses;
|
|
||||||
boost::mutex::scoped_lock l(ses->m_mutex);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cout << "adding torrent to session!\n";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ses->m_torrents.insert(
|
|
||||||
std::make_pair(m_data->info_hash, m_data->torrent_ptr)).first;
|
|
||||||
|
|
||||||
// remove ourself from the 'checking'-list
|
|
||||||
// (we're no longer in the checking state)
|
|
||||||
assert(ses->m_checkers.find(m_data->info_hash) != ses->m_checkers.end());
|
|
||||||
ses->m_checkers.erase(ses->m_checkers.find(m_data->info_hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session::add_torrent(const torrent_info& ti,
|
torrent_handle session::add_torrent(const torrent_info& ti,
|
||||||
const std::string& save_path)
|
const std::string& save_path)
|
||||||
{
|
{
|
||||||
// lock the session
|
|
||||||
boost::mutex::scoped_lock l(m_impl.m_mutex);
|
|
||||||
|
|
||||||
// is the torrent already active?
|
{
|
||||||
// TODO: this should throw
|
// lock the session
|
||||||
if (m_impl.m_torrents.find(ti.info_hash()) != m_impl.m_torrents.end())
|
boost::mutex::scoped_lock l(m_impl.m_mutex);
|
||||||
return torrent_handle(&m_impl, ti.info_hash());
|
|
||||||
|
|
||||||
// is the torrent currently being checked?
|
// is the torrent already active?
|
||||||
if (m_impl.m_checkers.find(ti.info_hash()) != m_impl.m_checkers.end())
|
// TODO: this should throw
|
||||||
return torrent_handle(&m_impl, ti.info_hash());
|
if (m_impl.find_torrent(ti.info_hash()))
|
||||||
|
return torrent_handle(&m_impl, &m_checker_impl, ti.info_hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// lock the checker_thread
|
||||||
|
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
|
||||||
|
|
||||||
|
// is the torrent currently being checked?
|
||||||
|
// TODO: This should throw
|
||||||
|
if (m_checker_impl.find_torrent(ti.info_hash()))
|
||||||
|
return torrent_handle(&m_impl, &m_checker_impl, ti.info_hash());
|
||||||
|
}
|
||||||
|
|
||||||
// create the torrent and the data associated with
|
// create the torrent and the data associated with
|
||||||
// the checker thread and store it before starting
|
// the checker thread and store it before starting
|
||||||
|
@ -486,16 +529,21 @@ namespace libtorrent
|
||||||
// having them all run at the same time
|
// having them all run at the same time
|
||||||
boost::shared_ptr<torrent> torrent_ptr(new torrent(&m_impl, ti));
|
boost::shared_ptr<torrent> torrent_ptr(new torrent(&m_impl, ti));
|
||||||
|
|
||||||
boost::shared_ptr<detail::piece_checker_data> d(new detail::piece_checker_data);
|
detail::piece_checker_data d;
|
||||||
d->torrent_ptr = torrent_ptr;
|
d.torrent_ptr = torrent_ptr;
|
||||||
d->save_path = save_path;
|
d.save_path = save_path;
|
||||||
d->ses = &m_impl;
|
d.info_hash = ti.info_hash();
|
||||||
d->info_hash = ti.info_hash();
|
|
||||||
|
|
||||||
m_impl.m_checkers.insert(std::make_pair(ti.info_hash(), d));
|
// lock the checker thread
|
||||||
m_impl.m_checker_threads.create_thread(detail::piece_check_thread(d));
|
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
|
||||||
|
|
||||||
return torrent_handle(&m_impl, ti.info_hash());
|
// add the torrent to the queue to be checked
|
||||||
|
m_checker_impl.m_torrents.push_back(d);
|
||||||
|
// and notify the thread that it got another
|
||||||
|
// job in its queue
|
||||||
|
m_checker_impl.m_cond.notify_one();
|
||||||
|
|
||||||
|
return torrent_handle(&m_impl, &m_checker_impl, ti.info_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
void session::set_http_settings(const http_settings& s)
|
void session::set_http_settings(const http_settings& s)
|
||||||
|
@ -511,12 +559,26 @@ namespace libtorrent
|
||||||
m_impl.m_abort = true;
|
m_impl.m_abort = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_thread.join();
|
{
|
||||||
|
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
|
||||||
|
// abort the checker thread
|
||||||
|
m_checker_impl.m_abort = true;
|
||||||
|
|
||||||
// TODO: join the checking threads!
|
// abort the currently checking torrent
|
||||||
|
if (!m_checker_impl.m_torrents.empty())
|
||||||
|
{
|
||||||
|
m_checker_impl.m_torrents.front().abort = true;
|
||||||
|
}
|
||||||
|
m_checker_impl.m_cond.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread.join();
|
||||||
|
m_checker_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: document
|
// TODO: document
|
||||||
|
// TODO: if the first 4 charachters are printable
|
||||||
|
// maybe they should be considered a fingerprint?
|
||||||
std::string extract_fingerprint(const peer_id& p)
|
std::string extract_fingerprint(const peer_id& p)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
|
@ -332,7 +332,8 @@ bool libtorrent::storage::verify_piece(piece_file& file)
|
||||||
// and abortion information.
|
// and abortion information.
|
||||||
void libtorrent::storage::initialize_pieces(torrent* t,
|
void libtorrent::storage::initialize_pieces(torrent* t,
|
||||||
const boost::filesystem::path& path,
|
const boost::filesystem::path& path,
|
||||||
boost::shared_ptr<detail::piece_checker_data> data)
|
detail::piece_checker_data* data,
|
||||||
|
boost::mutex* mutex)
|
||||||
{
|
{
|
||||||
m_save_path = path;
|
m_save_path = path;
|
||||||
m_torrent_file = &t->torrent_file();
|
m_torrent_file = &t->torrent_file();
|
||||||
|
@ -451,7 +452,7 @@ void libtorrent::storage::initialize_pieces(torrent* t,
|
||||||
left_to_write -= chunksize;
|
left_to_write -= chunksize;
|
||||||
progress += chunksize;
|
progress += chunksize;
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(data->mutex);
|
boost::mutex::scoped_lock l(*mutex);
|
||||||
data->progress = static_cast<float>(progress) / total_bytes;
|
data->progress = static_cast<float>(progress) / total_bytes;
|
||||||
if (data->abort) return;
|
if (data->abort) return;
|
||||||
}
|
}
|
||||||
|
@ -459,7 +460,7 @@ void libtorrent::storage::initialize_pieces(torrent* t,
|
||||||
if (left_to_write > 0) f.write(zeros, left_to_write);
|
if (left_to_write > 0) f.write(zeros, left_to_write);
|
||||||
progress += left_to_write;
|
progress += left_to_write;
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(data->mutex);
|
boost::mutex::scoped_lock l(*mutex);
|
||||||
data->progress = static_cast<float>(progress) / total_bytes;
|
data->progress = static_cast<float>(progress) / total_bytes;
|
||||||
if (data->abort) return;
|
if (data->abort) return;
|
||||||
}
|
}
|
||||||
|
@ -483,7 +484,7 @@ void libtorrent::storage::initialize_pieces(torrent* t,
|
||||||
// std::cout << i+1 << " / " << m_torrent_file->num_pieces() << " missing: " << missing << "\r";
|
// std::cout << i+1 << " / " << m_torrent_file->num_pieces() << " missing: " << missing << "\r";
|
||||||
|
|
||||||
progress += m_torrent_file->piece_size(i);
|
progress += m_torrent_file->piece_size(i);
|
||||||
boost::mutex::scoped_lock l(data->mutex);
|
boost::mutex::scoped_lock l(*mutex);
|
||||||
data->progress = static_cast<float>(progress) / total_bytes;
|
data->progress = static_cast<float>(progress) / total_bytes;
|
||||||
if (data->abort) return;
|
if (data->abort) return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,7 +346,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
|
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
|
||||||
// TODO: the send buffer size should be controllable from the outside
|
// TODO: the send buffer size should be controllable from the outside
|
||||||
s->set_send_bufsize(2048);
|
// s->set_send_bufsize(2048);
|
||||||
s->connect(a);
|
s->connect(a);
|
||||||
boost::shared_ptr<peer_connection> c(new peer_connection(m_ses, this, s, id));
|
boost::shared_ptr<peer_connection> c(new peer_connection(m_ses, this, s, id));
|
||||||
detail::session_impl::connection_map::iterator p =
|
detail::session_impl::connection_map::iterator p =
|
||||||
|
@ -403,15 +403,12 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<torrent_handle::state_t, float> torrent::status() const
|
torrent_status torrent::status() const
|
||||||
{
|
{
|
||||||
// TODO: report progress on block-level.
|
torrent_status st;
|
||||||
// make sure to handle the case where a piece
|
|
||||||
// fails the hash-check
|
|
||||||
const std::vector<bool>& p = m_storage.pieces();
|
const std::vector<bool>& p = m_storage.pieces();
|
||||||
int num_pieces = std::accumulate(p.begin(), p.end(), 0);
|
int num_pieces = std::accumulate(p.begin(), p.end(), 0);
|
||||||
if (num_pieces == p.size())
|
|
||||||
return std::make_pair(torrent_handle::seeding, 1.f);
|
|
||||||
|
|
||||||
int total_blocks
|
int total_blocks
|
||||||
= (m_torrent_file.total_size()+m_block_size-1)/m_block_size;
|
= (m_torrent_file.total_size()+m_block_size-1)/m_block_size;
|
||||||
|
@ -420,9 +417,18 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(m_unverified_blocks == m_picker.unverified_blocks());
|
assert(m_unverified_blocks == m_picker.unverified_blocks());
|
||||||
|
|
||||||
return std::make_pair(torrent_handle::downloading,
|
// TODO: Implement total download and total_upload
|
||||||
(num_pieces * blocks_per_piece + m_unverified_blocks)
|
st.total_download = 0;
|
||||||
/ static_cast<float>(total_blocks));
|
st.total_upload = 0;
|
||||||
|
st.progress = (num_pieces * blocks_per_piece + m_unverified_blocks)
|
||||||
|
/ static_cast<float>(total_blocks);
|
||||||
|
|
||||||
|
if (num_pieces == p.size())
|
||||||
|
st.state = torrent_status::seeding;
|
||||||
|
else
|
||||||
|
st.state = torrent_status::downloading;
|
||||||
|
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,24 +63,48 @@ namespace std
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
std::pair<torrent_handle::state_t, float> torrent_handle::status() const
|
torrent_status torrent_handle::status() const
|
||||||
{
|
{
|
||||||
if (m_ses == 0) return std::make_pair(invalid_handle, 0.f);
|
if (m_ses == 0)
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
||||||
|
|
||||||
torrent* t = m_ses->find_active_torrent(m_info_hash);
|
|
||||||
if (t != 0) return t->status();
|
|
||||||
|
|
||||||
detail::piece_checker_data* d = m_ses->find_checking_torrent(m_info_hash);
|
|
||||||
|
|
||||||
if (d != 0)
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(d->mutex);
|
torrent_status st;
|
||||||
return std::make_pair(checking_files, d->progress);
|
st.total_download = 0;
|
||||||
|
st.total_download = 0;
|
||||||
|
st.progress = 0.f;
|
||||||
|
st.state = torrent_status::invalid_handle;
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(invalid_handle, 0.f);
|
{
|
||||||
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||||
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
||||||
|
if (t != 0) return t->status();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
||||||
|
|
||||||
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
||||||
|
if (d != 0)
|
||||||
|
{
|
||||||
|
torrent_status st;
|
||||||
|
st.total_download = 0;
|
||||||
|
st.total_upload = 0;
|
||||||
|
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;
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
torrent_status st;
|
||||||
|
st.total_download = 0;
|
||||||
|
st.total_download = 0;
|
||||||
|
st.progress = 0.f;
|
||||||
|
st.state = torrent_status::invalid_handle;
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v)
|
void torrent_handle::get_peer_info(std::vector<peer_info>& v)
|
||||||
|
@ -89,10 +113,8 @@ namespace libtorrent
|
||||||
if (m_ses == 0) return;
|
if (m_ses == 0) return;
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||||
|
|
||||||
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i = m_ses->m_torrents.find(m_info_hash);
|
const torrent* t = m_ses->find_torrent(m_info_hash);
|
||||||
if (i == m_ses->m_torrents.end()) return;
|
if (t == 0) return;
|
||||||
|
|
||||||
const torrent* t = boost::get_pointer(i->second);
|
|
||||||
|
|
||||||
for (std::vector<peer_connection*>::const_iterator i = t->begin();
|
for (std::vector<peer_connection*>::const_iterator i = t->begin();
|
||||||
i != t->end();
|
i != t->end();
|
||||||
|
@ -124,27 +146,29 @@ namespace libtorrent
|
||||||
void torrent_handle::abort()
|
void torrent_handle::abort()
|
||||||
{
|
{
|
||||||
if (m_ses == 0) return;
|
if (m_ses == 0) return;
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
|
||||||
|
|
||||||
torrent* t = m_ses->find_active_torrent(m_info_hash);
|
|
||||||
if (t != 0)
|
|
||||||
{
|
{
|
||||||
t->abort();
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||||
m_ses = 0;
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
||||||
return;
|
if (t != 0)
|
||||||
|
{
|
||||||
|
t->abort();
|
||||||
|
m_ses = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::piece_checker_data* d = m_ses->find_checking_torrent(m_info_hash);
|
|
||||||
|
|
||||||
if (d != 0)
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(d->mutex);
|
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
||||||
d->abort = true;
|
|
||||||
// remove the checker. It will abort itself and
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
||||||
// close the thread now.
|
if (d != 0)
|
||||||
m_ses->m_checkers.erase(m_ses->m_checkers.find(m_info_hash));
|
{
|
||||||
m_ses = 0;
|
d->abort = true;
|
||||||
return;
|
m_ses = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ses = 0;
|
m_ses = 0;
|
||||||
|
|
Loading…
Reference in New Issue