diff --git a/docs/index.html b/docs/index.html
index 526a93185..69db98026 100755
--- a/docs/index.html
+++ b/docs/index.html
@@ -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;
};
-
-
progress() and state()is not implemented yet.
+
+abort() 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.
+
-progress() 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 state(), it will return one of
-the following:
+status() will return a structure with information about the status of this
+torrent. It contains the following fields:
+
+
+
+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;
+};
+
+
+
+progress 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 state member, it will be one of the following:
+
+
+ queued_for_cecking
+ |
+
+ 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.
+ |
+
checking_files
|
The torrent has not started its download yet, and is currently checking existing
- files or is queued for having its files checked.
- |
-
-
-
- connecting_to_tracker
- |
-
- 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.
|
@@ -520,9 +547,8 @@ the following:
-abort() 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.
+total_download and total_upload is the number of bytes downloaded and
+uploaded to all peers, accumulated.
diff --git a/examples/client_test.cpp b/examples/client_test.cpp
index 0b85251db..b81e086ee 100755
--- a/examples/client_test.cpp
+++ b/examples/client_test.cpp
@@ -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(val) + prefix[i];
+ val /= 1024.f;
+ }
+ return boost::lexical_cast(val) + prefix[i];
+}
+
int main(int argc, char* argv[])
{
using namespace libtorrent;
@@ -97,10 +111,6 @@ int main(int argc, char* argv[])
}
}
- std::pair prev_status
- = std::make_pair(torrent_handle::invalid_handle, 0.f);
-
-
std::vector 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 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::iterator i = peers.begin();
- i != peers.end();
+ for (std::vector::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::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)
diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp
index 2f69879c7..24e7cdd75 100755
--- a/include/libtorrent/entry.hpp
+++ b/include/libtorrent/entry.hpp
@@ -199,6 +199,9 @@ namespace libtorrent
data_type m_type;
#if defined(_MSC_VER)
+
+ // workaround for msvc-bug.
+ // assumes sizeof(map) == sizeof(map)
union
{
char data[detail::max4
#include
#include
+#include
#include
#include
@@ -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_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& p)
- : m_data(p)
- {}
+ checker_impl(session_impl* s): m_ses(s), m_abort(false) {}
void operator()();
- boost::shared_ptr 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 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 > 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 > m_torrents;
connection_map m_connections;
- // a list of all torrents that are currently checking
- // their files (in separate threads)
- std::map
- > 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 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;
};
}
diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp
index 7a75ea829..265d58a6a 100755
--- a/include/libtorrent/storage.hpp
+++ b/include/libtorrent/storage.hpp
@@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include
#include
+#include
#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 data);
+ detail::piece_checker_data* data,
+ boost::mutex* mutex);
int bytes_left() const { return m_bytes_left; }
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index 16fb09df8..0b63db4ae 100755
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -100,10 +100,11 @@ namespace libtorrent
void print(std::ostream& os) const;
- void allocate_files(boost::shared_ptr 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 status() const;
+ torrent_status status() const;
void connect_to_peer(const address& a, const peer_id& id);
diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp
index 216d5212e..ec6c8ee37 100755
--- a/include/libtorrent/torrent_handle.hpp
+++ b/include/libtorrent/torrent_handle.hpp
@@ -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& v);
void abort();
- enum state_t
- {
- invalid_handle,
- checking_files,
- connecting_to_tracker,
- downloading,
- seeding
- };
- std::pair 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*?
};
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index 3d568820c..3db5d4a86 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -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!
diff --git a/src/session.cpp b/src/session.cpp
index 5d8832a77..4af661651 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -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::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 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 > writable_clients;
std::vector > 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 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 >::iterator i = m_torrents.begin();
+ for (std::map >::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 >::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 >::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 >::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_ptr(new torrent(&m_impl, ti));
- boost::shared_ptr 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;
diff --git a/src/storage.cpp b/src/storage.cpp
index 1503ed9ac..fa162d69e 100755
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -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 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(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(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(progress) / total_bytes;
if (data->abort) return;
}
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 93fa3beba..5779ed40f 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -346,7 +346,7 @@ namespace libtorrent
{
boost::shared_ptr 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 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::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& 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(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(total_blocks);
+
+ if (num_pieces == p.size())
+ st.state = torrent_status::seeding;
+ else
+ st.state = torrent_status::downloading;
+
+ return st;
}
}
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 9a010c414..b64cf0251 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -63,24 +63,48 @@ namespace std
namespace libtorrent
{
- std::pair 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& v)
@@ -89,10 +113,8 @@ namespace libtorrent
if (m_ses == 0) return;
boost::mutex::scoped_lock l(m_ses->m_mutex);
- std::map >::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::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;