*** 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(); 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>

View File

@ -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)

View File

@ -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)

View File

@ -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;
}; };
} }

View File

@ -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; }

View File

@ -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);

View File

@ -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*?
}; };

View File

@ -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!

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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;