*** empty log message ***

This commit is contained in:
Arvid Norberg 2003-10-31 04:02:51 +00:00
parent d7f92afea3
commit 6466b46573
12 changed files with 416 additions and 295 deletions

View File

@ -455,7 +455,6 @@ struct torrent_handle
{
torrent_handle();
float progress() const;
void get_peer_info(std::vector<peer_info>& v);
void abort();
@ -466,37 +465,65 @@ struct torrent_handle
downloading,
seeding
};
state_t state() const;
torrent_status status() const;
};
</pre>
<!-- TODO: temporary comment -->
<p><tt>progress()</tt> and <tt>state()</tt>is not implemented yet</tt>.</p>
<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>
<tt>progress()</tt> will return a value in the range [0, 1], that represents the progress
of the torrent's current task. It may be checking files, connecting to tracker, or downloading
etc. You can get the torrent's current task bu calling <tt>state()</tt>, it will return one of
the following:
<tt>status()</tt> will return a structure with information about the status of this
torrent. It contains the following fields:
</p>
<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>
<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>
<td>
<tt>checking_files</tt>
</td>
<td>
The torrent has not started its download yet, and is currently checking existing
files or is queued for having its files checked.
</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.
files.
</td>
</tr>
<tr>
@ -520,9 +547,8 @@ the following:
</table>
<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.
<tt>total_download</tt> and <tt>total_upload</tt> is the number of bytes downloaded and
uploaded to all peers, accumulated.
</p>
<p>

View File

@ -56,6 +56,20 @@ bool sleep_and_input(char* c)
#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[])
{
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;
for (;;)
@ -111,63 +121,55 @@ int main(int argc, char* argv[])
if (c == 'q') break;
}
// just print info from the first torrent
torrent_handle h = handles.front();
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();
for (std::vector<torrent_handle>::iterator i = handles.begin();
i != handles.end();
++i)
{
down += i->down_speed;
up += i->up_speed;
total_down += i->total_download;
total_up += i->total_upload;
torrent_status s = i->status();
switch(s.state)
{
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.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";
std::cout << "----\n";
}
}
catch (std::exception& e)

View File

@ -199,6 +199,9 @@ namespace libtorrent
data_type m_type;
#if defined(_MSC_VER)
// workaround for msvc-bug.
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
union
{
char data[detail::max4<sizeof(list_type)

View File

@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include <set>
#include <list>
#include <deque>
#include <boost/limits.hpp>
#include <boost/tuple/tuple.hpp>
@ -86,21 +87,13 @@ namespace libtorrent
// thread that initialize pieces
struct piece_checker_data
{
piece_checker_data(): abort(false) {}
piece_checker_data(): progress(0.f), abort(false) {}
boost::shared_ptr<torrent> torrent_ptr;
std::string save_path;
// when the files has been checked
// the torrent is added to the session
session_impl* ses;
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()
// and represents the progress. It should be a
// value in the range [0, 1]
@ -112,42 +105,51 @@ namespace libtorrent
bool abort;
};
struct piece_check_thread
struct checker_impl: boost::noncopyable
{
piece_check_thread(const boost::shared_ptr<piece_checker_data>& p)
: m_data(p)
{}
checker_impl(session_impl* s): m_ses(s), m_abort(false) {}
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
// 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;
session_impl(const std::string& fingerprint);
session_impl(int listen_port, const std::string& fingerprint);
void operator()();
// must be locked to access the data
// in this struct
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;
std::map<sha1_hash, boost::shared_ptr<torrent> > m_torrents;
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
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.
// the selector can sleep while there's no activity on
// them
@ -158,13 +160,6 @@ namespace libtorrent
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)
boost::shared_ptr<logger> create_log(std::string name)
{
@ -177,34 +172,6 @@ namespace libtorrent
#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;
@ -216,8 +183,11 @@ namespace libtorrent
public:
session(int listen_port, const std::string& fingerprint = std::string())
: m_impl(fingerprint)
, m_thread(detail::main_loop_thread(listen_port, &m_impl)) {}
: m_impl(listen_port, fingerprint)
, m_checker_impl(&m_impl)
, m_thread(boost::ref(m_impl))
, m_checker_thread(boost::ref(m_checker_impl))
{}
~session();
@ -228,11 +198,20 @@ namespace libtorrent
private:
// data shared between the threads
// data shared between the main thread
// and the working thread
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
boost::thread m_thread;
// the thread that calls initialize_pieces()
// on all torrents before they start downloading
boost::thread m_checker_thread;
};
}

View File

@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/limits.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp>
#include "libtorrent/entry.hpp"
#include "libtorrent/torrent_info.hpp"
@ -145,7 +146,8 @@ namespace libtorrent
void initialize_pieces(torrent* t,
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; }

View File

@ -100,10 +100,11 @@ namespace libtorrent
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)
{
m_storage.initialize_pieces(this, save_path, data);
m_storage.initialize_pieces(this, save_path, data, mutex);
m_picker.files_checked(m_storage.pieces());
#ifndef NDEBUG
m_picker.integrity_check(this);
@ -117,7 +118,7 @@ namespace libtorrent
int bytes_uploaded() const { return m_bytes_uploaded; }
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);

View File

@ -44,8 +44,27 @@ namespace libtorrent
namespace detail
{
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
{
friend class session;
@ -54,27 +73,23 @@ namespace libtorrent
void get_peer_info(std::vector<peer_info>& v);
void abort();
enum state_t
{
invalid_handle,
checking_files,
connecting_to_tracker,
downloading,
seeding
};
std::pair<state_t, float> status() const;
torrent_status status() const;
// TODO: add a 'time to next announce' query.
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_chk(c)
, m_info_hash(h)
{}
detail::session_impl* m_ses;
detail::checker_impl* m_chk;
sha1_hash m_info_hash; // should be replaced with a torrent*?
};

View File

@ -638,7 +638,7 @@ void libtorrent::peer_connection::receive_data()
sha1_hash info_hash;
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)
{
// we couldn't find the torrent!

View File

@ -77,33 +77,98 @@ namespace libtorrent
{
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_tracker_manager(m_settings)
, m_listen_port(listen_port)
{
// ---- generate a peer id ----
std::srand(std::time(0));
// libtorrent's fingerprint
unsigned char fingerprint[] = "lt.";
const int len1 = std::min(cl_fprint.length(), (std::size_t)7);
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
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
std::fill(m_peer_id.begin()+len1+len2, m_peer_id.begin()+len1+len2+len3, 0);
assert(len1 + len2 + len3 == 12);
std::fill(m_peer_id.begin()+len1, m_peer_id.begin()+len1+len2, 0);
assert(len1 + len2 == 12);
// 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)
{
@ -112,14 +177,14 @@ namespace libtorrent
}
void session_impl::run(int listen_port)
void session_impl::operator()()
{
#if defined(TORRENT_VERBOSE_LOGGING)
m_logger = create_log("main session");
#endif
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
@ -128,19 +193,19 @@ namespace libtorrent
{
try
{
listener->listen(listen_port, 5);
listener->listen(m_listen_port, 5);
}
catch(network_error&)
{
if (listen_port > max_port) throw;
listen_port++;
if (m_listen_port > max_port) throw;
m_listen_port++;
continue;
}
break;
}
#if defined(TORRENT_VERBOSE_LOGGING)
(*m_logger) << "listening on port: " << listen_port << "\n";
(*m_logger) << "listening on port: " << m_listen_port << "\n";
#endif
m_selector.monitor_readability(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> > error_clients;
boost::posix_time::ptime timer = boost::posix_time::second_clock::local_time();
#ifdef TORRENT_DEBUG_SOCKETS
int num_loops = 0;
#endif
for(;;)
{
// 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);
boost::mutex::scoped_lock l(m_mutex);
#ifdef TORRENT_DEBUG_SOCKETS
num_loops++;
#endif
// +1 for the listen socket
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
@ -184,7 +255,7 @@ namespace libtorrent
++i)
{
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_torrents.clear();
@ -215,7 +286,7 @@ namespace libtorrent
(*m_logger) << s->sender().as_string() << " <== INCOMING CONNECTION\n";
#endif
// 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
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
// ************************
#ifdef TORRENT_DEBUG_SOCKETS
std::cout << "\nloops: " << num_loops << "\n";
assert(loops < 1300);
num_loops = 0;
#endif
// do the second_tick() on each connection
// this will update their statistics (download and upload speeds)
@ -361,12 +438,14 @@ namespace libtorrent
// check each torrent for abortion or
// 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();)
{
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();
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j = i;
++i;
@ -376,7 +455,7 @@ namespace libtorrent
else if (i->second->should_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));
}
++i;
@ -409,7 +488,7 @@ namespace libtorrent
// the return value from this function is valid only as long as the
// 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
= m_torrents.find(info_hash);
@ -417,67 +496,31 @@ namespace libtorrent
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,
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
if (m_impl.m_torrents.find(ti.info_hash()) != m_impl.m_torrents.end())
return torrent_handle(&m_impl, ti.info_hash());
{
// lock the session
boost::mutex::scoped_lock l(m_impl.m_mutex);
// is the torrent currently being checked?
if (m_impl.m_checkers.find(ti.info_hash()) != m_impl.m_checkers.end())
return torrent_handle(&m_impl, ti.info_hash());
// is the torrent already active?
// TODO: this should throw
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
// the checker thread and store it before starting
@ -486,16 +529,21 @@ namespace libtorrent
// having them all run at the same time
boost::shared_ptr<torrent> torrent_ptr(new torrent(&m_impl, ti));
boost::shared_ptr<detail::piece_checker_data> d(new detail::piece_checker_data);
d->torrent_ptr = torrent_ptr;
d->save_path = save_path;
d->ses = &m_impl;
d->info_hash = ti.info_hash();
detail::piece_checker_data d;
d.torrent_ptr = torrent_ptr;
d.save_path = save_path;
d.info_hash = ti.info_hash();
m_impl.m_checkers.insert(std::make_pair(ti.info_hash(), d));
m_impl.m_checker_threads.create_thread(detail::piece_check_thread(d));
// lock the checker thread
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)
@ -511,12 +559,26 @@ namespace libtorrent
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: if the first 4 charachters are printable
// maybe they should be considered a fingerprint?
std::string extract_fingerprint(const peer_id& p)
{
std::string ret;

View File

@ -332,7 +332,8 @@ bool libtorrent::storage::verify_piece(piece_file& file)
// and abortion information.
void libtorrent::storage::initialize_pieces(torrent* t,
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_torrent_file = &t->torrent_file();
@ -451,7 +452,7 @@ void libtorrent::storage::initialize_pieces(torrent* t,
left_to_write -= chunksize;
progress += chunksize;
boost::mutex::scoped_lock l(data->mutex);
boost::mutex::scoped_lock l(*mutex);
data->progress = static_cast<float>(progress) / total_bytes;
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);
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;
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";
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;
if (data->abort) return;
}

View File

@ -346,7 +346,7 @@ namespace libtorrent
{
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
// TODO: the send buffer size should be controllable from the outside
s->set_send_bufsize(2048);
// s->set_send_bufsize(2048);
s->connect(a);
boost::shared_ptr<peer_connection> c(new peer_connection(m_ses, this, s, id));
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.
// make sure to handle the case where a piece
// fails the hash-check
torrent_status st;
const std::vector<bool>& p = m_storage.pieces();
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
= (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());
return std::make_pair(torrent_handle::downloading,
(num_pieces * blocks_per_piece + m_unverified_blocks)
/ static_cast<float>(total_blocks));
// TODO: Implement total download and total_upload
st.total_download = 0;
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;
}
}

View File

@ -63,24 +63,48 @@ namespace std
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);
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)
if (m_ses == 0)
{
boost::mutex::scoped_lock l(d->mutex);
return std::make_pair(checking_files, d->progress);
torrent_status st;
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)
@ -89,10 +113,8 @@ namespace libtorrent
if (m_ses == 0) return;
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);
if (i == m_ses->m_torrents.end()) return;
const torrent* t = boost::get_pointer(i->second);
const torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) return;
for (std::vector<peer_connection*>::const_iterator i = t->begin();
i != t->end();
@ -124,27 +146,29 @@ namespace libtorrent
void torrent_handle::abort()
{
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();
m_ses = 0;
return;
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
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);
d->abort = true;
// remove the checker. It will abort itself and
// close the thread now.
m_ses->m_checkers.erase(m_ses->m_checkers.find(m_info_hash));
m_ses = 0;
return;
boost::mutex::scoped_lock l(m_chk->m_mutex);
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
{
d->abort = true;
m_ses = 0;
return;
}
}
m_ses = 0;