From 6466b46573da7b02f38196cb31c47632581a3f9e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 31 Oct 2003 04:02:51 +0000 Subject: [PATCH] *** empty log message *** --- docs/index.html | 68 +++++--- examples/client_test.cpp | 118 +++++++------ include/libtorrent/entry.hpp | 3 + include/libtorrent/session.hpp | 103 +++++------ include/libtorrent/storage.hpp | 4 +- include/libtorrent/torrent.hpp | 7 +- include/libtorrent/torrent_handle.hpp | 37 ++-- src/peer_connection.cpp | 2 +- src/session.cpp | 242 ++++++++++++++++---------- src/storage.cpp | 9 +- src/torrent.cpp | 26 +-- src/torrent_handle.cpp | 92 ++++++---- 12 files changed, 416 insertions(+), 295 deletions(-) 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:

+ + + + - - - - @@ -520,9 +547,8 @@ 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.

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