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