forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
1bd0a8234a
commit
d7f92afea3
1
Jamfile
1
Jamfile
|
@ -12,6 +12,7 @@ SOURCES =
|
|||
stat.cpp
|
||||
storage.cpp
|
||||
torrent.cpp
|
||||
torrent_handle.cpp
|
||||
torrent_info.cpp
|
||||
url_handler.cpp
|
||||
sha1.c
|
||||
|
|
|
@ -105,7 +105,7 @@ Then the makefile should be able to do the rest.
|
|||
<p>
|
||||
When building (with boost 1.30.2) on linux and solaris however, I found that I had to make the following
|
||||
modifications to the boost.date-time library. In the file:
|
||||
'boost-1.30.2/boost/date_time/gregorian_calendar.hpp' line 59. Add 'boost/date_time/'
|
||||
'boost-1.30.2/boost/date_time/gregorian_calendar.hpp' line 59. Prepend 'boost/date_time/'
|
||||
to the include path.
|
||||
</p>
|
||||
|
||||
|
@ -215,8 +215,7 @@ refers to a character (<tt>char</tt>). So, if you want to encode entry <tt>e</tt
|
|||
into a buffer in memory, you can do it like this:
|
||||
</p>
|
||||
|
||||
<code>
|
||||
std::vector<char> buffer;
|
||||
<code>std::vector<char> buffer;
|
||||
bencode(std::back_insert_iterator<std::vector<char> >(buf), e);
|
||||
</code>
|
||||
|
||||
|
@ -224,8 +223,7 @@ bencode(std::back_insert_iterator<std::vector<char> >(buf), e);
|
|||
If you want to decode a torrent file from a buffer in memory, you can do it like this:
|
||||
</p>
|
||||
|
||||
<code>
|
||||
std::vector<char> buffer;
|
||||
<code>std::vector<char> buffer;
|
||||
|
||||
// ...
|
||||
|
||||
|
@ -236,8 +234,7 @@ entry e = bdecode(buf.begin(), buf.end());
|
|||
Or, if you have a raw char buffer:
|
||||
</p>
|
||||
|
||||
<code>
|
||||
const char* buf;
|
||||
<code>const char* buf;
|
||||
|
||||
// ...
|
||||
|
||||
|
@ -318,8 +315,7 @@ can assign the value you want it to have.
|
|||
The typical code to get info from a torrent file will then look like this:
|
||||
</p>
|
||||
|
||||
<code>
|
||||
entry torrent_file;
|
||||
<code>entry torrent_file;
|
||||
|
||||
// ...
|
||||
|
||||
|
@ -369,6 +365,7 @@ public:
|
|||
entry::integer_type piece_length() const;
|
||||
std::size_t num_pieces() const;
|
||||
const sha1_hash& info_hash() const;
|
||||
const std::stirng& name() const;
|
||||
|
||||
void print(std::ostream& os) const;
|
||||
|
||||
|
@ -403,6 +400,10 @@ The <tt>print()</tt> function is there for debug purposes only. It will print th
|
|||
the torrent file to the given outstream.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt>name()</tt> returns the name of the torrent.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <tt>trackers()</tt> function will return a sorted vector of <tt>announce_entry</tt>.
|
||||
Each announce entry contains a string, which is the tracker url, and a tier index. The
|
||||
|
@ -544,6 +545,8 @@ struct peer_info
|
|||
address ip;
|
||||
float up_speed;
|
||||
float down_speed;
|
||||
unsigned int total_download;
|
||||
unsigned int total_upload;
|
||||
peer_id id;
|
||||
std::vector<bool> pieces;
|
||||
};
|
||||
|
@ -568,6 +571,12 @@ actual address and the port number. See <a href"#address">address</a> class.
|
|||
we have to and from this peer. These figures are updated aproximately once every second.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt>total_download</tt> and <tt>total_upload</tt> are the total number of bytes downloaded
|
||||
from and uploaded to this peer. These numbers do not include the protocol chatter, but only
|
||||
the payload data.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt>id</tt> is the peer's id as used in the bit torrent protocol. This id can be used to
|
||||
extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer
|
||||
|
@ -650,6 +659,42 @@ public:
|
|||
The iterators gives you access to individual bytes.
|
||||
</p>
|
||||
|
||||
<h2>hasher</h2>
|
||||
|
||||
<p>
|
||||
This class creates sha1-hashes. Its declaration looks like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
class hasher
|
||||
{
|
||||
public:
|
||||
hasher();
|
||||
|
||||
void update(const char* data, unsigned int len);
|
||||
sha1_hash final();
|
||||
void reset();
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You use it by first instantiating it, then call <tt>update()</tt> to feed it
|
||||
with data. i.e. you don't have to keep the entire buffer of which you want to
|
||||
create the hash in memory. You can feed the hasher parts of it at a time. When
|
||||
You have fed the hasher with all the data, you call <tt>final()</tt> and it
|
||||
will return the sha1-hash of the data.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you want to reuse the hasher object once you have created a hash, you have to
|
||||
call <tt>reset()</tt> to reinitialize it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The sha1-algorithm used was implemented by Steve Reid and released as public domain.
|
||||
For more info, see <tt>src/sha1.c</tt>.
|
||||
</p>
|
||||
|
||||
<h1>Credits</h1>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -40,6 +40,21 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/http_settings.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <conio.h>
|
||||
|
||||
bool sleep_and_input(char* c)
|
||||
{
|
||||
Sleep(500);
|
||||
if (kbhit())
|
||||
{
|
||||
*c = getch();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
@ -62,7 +77,7 @@ int main(int argc, char* argv[])
|
|||
try
|
||||
{
|
||||
std::vector<torrent_handle> handles;
|
||||
session s(6881, "ex-01");
|
||||
session s(6881, "E\x1");
|
||||
|
||||
s.set_http_settings(settings);
|
||||
for (int i = 0; i < argc-1; ++i)
|
||||
|
@ -82,19 +97,82 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
while (!handles.empty())
|
||||
{
|
||||
int a;
|
||||
std::cin >> a;
|
||||
handles.back().abort();
|
||||
handles.pop_back();
|
||||
}
|
||||
std::pair<torrent_handle::state_t, float> prev_status
|
||||
= std::make_pair(torrent_handle::invalid_handle, 0.f);
|
||||
|
||||
|
||||
std::vector<peer_info> peers;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char c;
|
||||
if (sleep_and_input(&c))
|
||||
{
|
||||
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();
|
||||
++i)
|
||||
{
|
||||
down += i->down_speed;
|
||||
up += i->up_speed;
|
||||
total_down += i->total_download;
|
||||
total_up += i->total_upload;
|
||||
}
|
||||
|
||||
std::cout.width(2);
|
||||
std::cout.precision(2);
|
||||
|
||||
std::cout << "p:" << num_peers;
|
||||
|
||||
std::cout.width(6);
|
||||
std::cout.precision(6);
|
||||
|
||||
std::cout << " d:("
|
||||
<< total_down/1024.f << " kB) " << down/1024.f << " kB/s up:("
|
||||
<< total_up/1024.f << " kB) " << up/1024.f << " kB/s \r";
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,14 @@ namespace libtorrent
|
|||
void update(const char* data, unsigned int len)
|
||||
{ SHA1Update(&m_context, reinterpret_cast<unsigned char*>(const_cast<char*>(data)), len); }
|
||||
|
||||
void final(sha1_hash& digest) { SHA1Final(digest.begin(), &m_context); }
|
||||
sha1_hash final()
|
||||
{
|
||||
sha1_hash digest;
|
||||
SHA1Final(digest.begin(), &m_context);
|
||||
return digest;
|
||||
}
|
||||
|
||||
void reset() { SHA1Init(&m_context); }
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ namespace libtorrent
|
|||
address ip;
|
||||
float up_speed;
|
||||
float down_speed;
|
||||
unsigned int total_download;
|
||||
unsigned int total_upload;
|
||||
peer_id id;
|
||||
std::vector<bool> pieces;
|
||||
};
|
||||
|
|
|
@ -113,6 +113,8 @@ namespace libtorrent
|
|||
|
||||
bool is_piece_finished(int index) const;
|
||||
|
||||
int blocks_in_piece(int index) const;
|
||||
int unverified_blocks() const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// used in debug mode
|
||||
|
@ -205,6 +207,14 @@ namespace libtorrent
|
|||
|
||||
};
|
||||
|
||||
inline int piece_picker::blocks_in_piece(int index) const
|
||||
{
|
||||
if (index+1 == m_piece_map.size())
|
||||
return m_blocks_in_last_piece;
|
||||
else
|
||||
return m_blocks_per_piece;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // TORRENT_PIECE_PICKER_HPP_INCLUDED
|
||||
|
|
|
@ -82,8 +82,12 @@ namespace libtorrent
|
|||
namespace detail
|
||||
{
|
||||
|
||||
// this data is shared between the main thread and the
|
||||
// thread that initialize pieces
|
||||
struct piece_checker_data
|
||||
{
|
||||
piece_checker_data(): abort(false) {}
|
||||
|
||||
boost::shared_ptr<torrent> torrent_ptr;
|
||||
std::string save_path;
|
||||
|
||||
|
@ -97,7 +101,15 @@ namespace libtorrent
|
|||
// 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]
|
||||
float progress;
|
||||
|
||||
// abort defaults to false and is typically
|
||||
// filled in by torrent_handle when the user
|
||||
// aborts the torrent
|
||||
bool abort;
|
||||
};
|
||||
|
||||
struct piece_check_thread
|
||||
|
@ -128,7 +140,9 @@ namespace libtorrent
|
|||
|
||||
// a list of all torrents that are currently checking
|
||||
// their files (in separate threads)
|
||||
std::map<sha1_hash, boost::shared_ptr<piece_checker_data> > m_checkers;
|
||||
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
|
||||
|
@ -146,7 +160,9 @@ namespace libtorrent
|
|||
|
||||
void run(int listen_port);
|
||||
|
||||
torrent* find_torrent(const sha1_hash& info_hash);
|
||||
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)
|
||||
|
@ -215,8 +231,8 @@ namespace libtorrent
|
|||
// data shared between the threads
|
||||
detail::session_impl m_impl;
|
||||
|
||||
// the main working thread
|
||||
boost::thread m_thread;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -249,6 +249,8 @@ namespace libtorrent
|
|||
, std::vector<boost::shared_ptr<socket> >& writable
|
||||
, std::vector<boost::shared_ptr<socket> >& error);
|
||||
|
||||
int count_read_monitors() const { return m_readable.size(); }
|
||||
|
||||
private:
|
||||
|
||||
std::vector<boost::shared_ptr<socket> > m_readable;
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace libtorrent
|
|||
float up_peak() const { return m_peak_uploaded_per_second; }
|
||||
|
||||
unsigned int total_upload() const { return m_total_upload; }
|
||||
unsigned int total_dowload() const { return m_total_download; }
|
||||
unsigned int total_download() const { return m_total_download; }
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -60,7 +60,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class piece_checker_data;
|
||||
}
|
||||
class session;
|
||||
|
||||
struct file_allocation_failed: std::exception
|
||||
|
@ -140,7 +143,9 @@ namespace libtorrent
|
|||
friend class piece_file;
|
||||
public:
|
||||
|
||||
void initialize_pieces(torrent* t, const boost::filesystem::path& path);
|
||||
void initialize_pieces(torrent* t,
|
||||
const boost::filesystem::path& path,
|
||||
boost::shared_ptr<detail::piece_checker_data> data);
|
||||
|
||||
int bytes_left() const { return m_bytes_left; }
|
||||
|
||||
|
|
|
@ -100,9 +100,10 @@ namespace libtorrent
|
|||
|
||||
void print(std::ostream& os) const;
|
||||
|
||||
void allocate_files(const std::string& save_path)
|
||||
void allocate_files(boost::shared_ptr<detail::piece_checker_data> data,
|
||||
const std::string& save_path)
|
||||
{
|
||||
m_storage.initialize_pieces(this, save_path);
|
||||
m_storage.initialize_pieces(this, save_path, data);
|
||||
m_picker.files_checked(m_storage.pieces());
|
||||
#ifndef NDEBUG
|
||||
m_picker.integrity_check(this);
|
||||
|
@ -214,6 +215,10 @@ namespace libtorrent
|
|||
logger* spawn_logger(const char* title);
|
||||
#endif
|
||||
|
||||
// the number of blocks downloaded
|
||||
// that hasn't been verified yet
|
||||
int m_unverified_blocks;
|
||||
|
||||
private:
|
||||
|
||||
void try_next_tracker();
|
||||
|
|
|
@ -64,6 +64,9 @@ namespace libtorrent
|
|||
};
|
||||
std::pair<state_t, float> status() const;
|
||||
|
||||
// TODO: add a 'time to next announce' query.
|
||||
|
||||
|
||||
private:
|
||||
|
||||
torrent_handle(detail::session_impl* s, const sha1_hash& h)
|
||||
|
|
|
@ -385,10 +385,13 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
// pop the request that just finished
|
||||
// from the download queue
|
||||
m_download_queue.erase(m_download_queue.begin());
|
||||
m_torrent->m_unverified_blocks++;
|
||||
|
||||
// did we just finish the piece?
|
||||
if (picker.is_piece_finished(index))
|
||||
{
|
||||
m_torrent->m_unverified_blocks -= picker.blocks_in_piece(index);
|
||||
|
||||
bool verified = m_torrent->filesystem()->verify_piece(m_receiving_piece);
|
||||
if (verified)
|
||||
{
|
||||
|
@ -563,199 +566,205 @@ void libtorrent::peer_connection::send_have(int index)
|
|||
// throws exception when the client should be disconnected
|
||||
void libtorrent::peer_connection::receive_data()
|
||||
{
|
||||
int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos);
|
||||
|
||||
// (*m_logger) << "<== RECV [ size: " << received << " ]\n";
|
||||
|
||||
if (received == 0) throw network_error(0);
|
||||
if (received < 0)
|
||||
for(;;)
|
||||
{
|
||||
if (m_socket->last_error() == socket::would_block) return;
|
||||
// the connection was closed
|
||||
throw network_error(0);
|
||||
}
|
||||
int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos);
|
||||
|
||||
if (received > 0)
|
||||
{
|
||||
m_statistics.received_bytes(received);
|
||||
m_last_receive = boost::posix_time::second_clock::local_time();
|
||||
// connection closed
|
||||
if (received == 0) throw network_error(0);
|
||||
|
||||
m_recv_pos += received;
|
||||
|
||||
if (m_recv_pos == m_packet_size)
|
||||
// an error
|
||||
if (received < 0)
|
||||
{
|
||||
switch(m_state)
|
||||
// would block means that no data was ready to be received
|
||||
if (m_socket->last_error() == socket::would_block) return;
|
||||
|
||||
// the connection was closed
|
||||
throw network_error(0);
|
||||
}
|
||||
|
||||
if (received > 0)
|
||||
{
|
||||
m_statistics.received_bytes(received);
|
||||
m_last_receive = boost::posix_time::second_clock::local_time();
|
||||
|
||||
m_recv_pos += received;
|
||||
|
||||
if (m_recv_pos == m_packet_size)
|
||||
{
|
||||
case read_protocol_length:
|
||||
m_packet_size = reinterpret_cast<unsigned char&>(m_recv_buffer[0]);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol length: " << m_packet_size << "\n";
|
||||
#endif
|
||||
m_state = read_protocol_version;
|
||||
if (m_packet_size != 19)
|
||||
throw network_error(0);
|
||||
m_recv_buffer.resize(m_packet_size);
|
||||
m_recv_pos = 0;
|
||||
break;
|
||||
|
||||
|
||||
case read_protocol_version:
|
||||
switch(m_state)
|
||||
{
|
||||
const char* protocol_version = "BitTorrent protocol";
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol name: " << std::string(m_recv_buffer.begin(), m_recv_buffer.end()) << "\n";
|
||||
#endif
|
||||
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), protocol_version))
|
||||
{
|
||||
// unknown protocol, close connection
|
||||
case read_protocol_length:
|
||||
m_packet_size = reinterpret_cast<unsigned char&>(m_recv_buffer[0]);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol length: " << m_packet_size << "\n";
|
||||
#endif
|
||||
m_state = read_protocol_version;
|
||||
if (m_packet_size != 19)
|
||||
throw network_error(0);
|
||||
}
|
||||
m_state = read_info_hash;
|
||||
m_packet_size = 28;
|
||||
m_recv_buffer.resize(m_packet_size);
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(28);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
|
||||
case read_info_hash:
|
||||
{
|
||||
// ok, now we have got enough of the handshake. Is this connection
|
||||
// attached to a torrent?
|
||||
case read_protocol_version:
|
||||
{
|
||||
const char* protocol_version = "BitTorrent protocol";
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol name: " << std::string(m_recv_buffer.begin(), m_recv_buffer.end()) << "\n";
|
||||
#endif
|
||||
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), protocol_version))
|
||||
{
|
||||
// unknown protocol, close connection
|
||||
throw network_error(0);
|
||||
}
|
||||
m_state = read_info_hash;
|
||||
m_packet_size = 28;
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(28);
|
||||
}
|
||||
break;
|
||||
|
||||
if (m_torrent == 0)
|
||||
|
||||
case read_info_hash:
|
||||
{
|
||||
// no, we have to see if there's a torrent with the
|
||||
// info_hash we got from the peer
|
||||
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_torrent(info_hash);
|
||||
// ok, now we have got enough of the handshake. Is this connection
|
||||
// attached to a torrent?
|
||||
|
||||
if (m_torrent == 0)
|
||||
{
|
||||
// we couldn't find the torrent!
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " couldn't find a torrent with the given info_hash\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
// no, we have to see if there's a torrent with the
|
||||
// info_hash we got from the peer
|
||||
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);
|
||||
if (m_torrent == 0)
|
||||
{
|
||||
// we couldn't find the torrent!
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " couldn't find a torrent with the given info_hash\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
}
|
||||
m_torrent->attach_peer(this);
|
||||
|
||||
// assume the other end has no pieces
|
||||
m_have_piece.resize(m_torrent->torrent_file().num_pieces());
|
||||
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
|
||||
|
||||
// yes, we found the torrent
|
||||
// reply with our handshake
|
||||
std::copy(m_recv_buffer.begin()+28, m_recv_buffer.begin() + 48, (char*)m_peer_id.begin());
|
||||
send_handshake();
|
||||
send_bitfield();
|
||||
}
|
||||
m_torrent->attach_peer(this);
|
||||
|
||||
// assume the other end has no pieces
|
||||
m_have_piece.resize(m_torrent->torrent_file().num_pieces());
|
||||
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
|
||||
|
||||
// yes, we found the torrent
|
||||
// reply with our handshake
|
||||
std::copy(m_recv_buffer.begin()+28, m_recv_buffer.begin() + 48, (char*)m_peer_id.begin());
|
||||
send_handshake();
|
||||
send_bitfield();
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify info hash
|
||||
if (!std::equal(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (const char*)m_torrent->torrent_file().info_hash().begin()))
|
||||
else
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received invalid info_hash\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
// verify info hash
|
||||
if (!std::equal(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (const char*)m_torrent->torrent_file().info_hash().begin()))
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received invalid info_hash\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
}
|
||||
}
|
||||
|
||||
m_state = read_peer_id;
|
||||
m_packet_size = 20;
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(20);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " info_hash received\n";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = read_peer_id;
|
||||
m_packet_size = 20;
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(20);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " info_hash received\n";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case read_peer_id:
|
||||
{
|
||||
if (m_active)
|
||||
case read_peer_id:
|
||||
{
|
||||
// verify peer_id
|
||||
// TODO: It seems like the original client ignores to check the peer id
|
||||
// can this be correct?
|
||||
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (const char*)m_peer_id.begin()))
|
||||
if (m_active)
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " invalid peer_id (it doesn't equal the one from the tracker)\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
// verify peer_id
|
||||
// TODO: It seems like the original client ignores to check the peer id
|
||||
// can this be correct?
|
||||
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (const char*)m_peer_id.begin()))
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " invalid peer_id (it doesn't equal the one from the tracker)\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check to make sure we don't have another connection with the same
|
||||
// info_hash and peer_id. If we do. close this connection.
|
||||
std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)m_peer_id.begin());
|
||||
if (m_torrent->num_connections(m_peer_id) > 1)
|
||||
else
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " duplicate connection, closing\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
// check to make sure we don't have another connection with the same
|
||||
// info_hash and peer_id. If we do. close this connection.
|
||||
std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)m_peer_id.begin());
|
||||
if (m_torrent->num_connections(m_peer_id) > 1)
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " duplicate connection, closing\n";
|
||||
#endif
|
||||
throw network_error(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(4);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received peer_id\n";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case read_packet_size:
|
||||
// convert from big endian to native byte order
|
||||
m_packet_size = read_int(&m_recv_buffer[0]);
|
||||
// don't accept packets larger than 1 MB
|
||||
if (m_packet_size > 1024*1024 || m_packet_size < 0)
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " packet too large (packet_size > 1 Megabyte), abort\n";
|
||||
#endif
|
||||
// packet too large
|
||||
throw network_error(0);
|
||||
}
|
||||
|
||||
if (m_packet_size == 0)
|
||||
{
|
||||
// keepalive message
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = read_packet;
|
||||
m_recv_buffer.resize(m_packet_size);
|
||||
}
|
||||
m_recv_pos = 0;
|
||||
break;
|
||||
|
||||
case read_packet:
|
||||
if (!dispatch_message())
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received invalid packet\n";
|
||||
#endif
|
||||
// invalid message
|
||||
throw network_error(0);
|
||||
m_recv_pos = 0;
|
||||
m_recv_buffer.resize(4);
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received peer_id\n";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
m_recv_buffer.resize(4);
|
||||
m_recv_pos = 0;
|
||||
break;
|
||||
|
||||
case read_packet_size:
|
||||
// convert from big endian to native byte order
|
||||
m_packet_size = read_int(&m_recv_buffer[0]);
|
||||
// don't accept packets larger than 1 MB
|
||||
if (m_packet_size > 1024*1024 || m_packet_size < 0)
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " packet too large (packet_size > 1 Megabyte), abort\n";
|
||||
#endif
|
||||
// packet too large
|
||||
throw network_error(0);
|
||||
}
|
||||
|
||||
if (m_packet_size == 0)
|
||||
{
|
||||
// keepalive message
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = read_packet;
|
||||
m_recv_buffer.resize(m_packet_size);
|
||||
}
|
||||
m_recv_pos = 0;
|
||||
break;
|
||||
|
||||
case read_packet:
|
||||
if (!dispatch_message())
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_logger) << m_socket->sender().as_string() << " received invalid packet\n";
|
||||
#endif
|
||||
// invalid message
|
||||
throw network_error(0);
|
||||
}
|
||||
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
m_recv_buffer.resize(4);
|
||||
m_recv_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,8 +452,7 @@ namespace libtorrent
|
|||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
|
||||
assert(i != m_downloads.end());
|
||||
assert(i->finished_blocks.count() <= m_blocks_per_piece);
|
||||
int max_blocks = m_blocks_per_piece;
|
||||
if (index+1 == m_piece_map.size()) max_blocks = m_blocks_in_last_piece;
|
||||
int max_blocks = blocks_in_piece(index);
|
||||
if (i->finished_blocks.count() != max_blocks) return false;
|
||||
|
||||
assert(i->requested_blocks.count() == max_blocks);
|
||||
|
@ -561,4 +560,16 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
int piece_picker::unverified_blocks() const
|
||||
{
|
||||
int counter = 0;
|
||||
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
|
||||
i != m_downloads.end();
|
||||
++i)
|
||||
{
|
||||
counter += i->finished_blocks.count();
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -172,7 +172,9 @@ namespace libtorrent
|
|||
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
||||
std::cout << "peers: " << m_connections.size() << "\n";
|
||||
// +1 for the listen socket
|
||||
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
|
||||
|
||||
if (m_abort)
|
||||
{
|
||||
m_tracker_manager.abort_all_requests();
|
||||
|
@ -407,16 +409,21 @@ namespace libtorrent
|
|||
|
||||
// the return value from this function is valid only as long as the
|
||||
// session is locked!
|
||||
torrent* session_impl::find_torrent(const sha1_hash& info_hash)
|
||||
torrent* session_impl::find_active_torrent(const sha1_hash& info_hash)
|
||||
{
|
||||
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
||||
= m_torrents.find(info_hash);
|
||||
if (i != m_torrents.end()) return boost::get_pointer(i->second);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::map<sha1_hash, boost::shared_ptr<detail::piece_checker_data> >::iterator j
|
||||
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 (j != m_checkers.end())
|
||||
return boost::get_pointer(j->second->torrent_ptr);
|
||||
|
||||
if (i != m_checkers.end())
|
||||
return boost::get_pointer(i->second);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -431,7 +438,7 @@ namespace libtorrent
|
|||
// new allocation model)
|
||||
try
|
||||
{
|
||||
m_data->torrent_ptr->allocate_files(m_data->save_path);
|
||||
m_data->torrent_ptr->allocate_files(m_data, m_data->save_path);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -442,6 +449,10 @@ namespace libtorrent
|
|||
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;
|
||||
|
||||
|
@ -453,7 +464,8 @@ namespace libtorrent
|
|||
|
||||
}
|
||||
|
||||
torrent_handle session::add_torrent(const torrent_info& ti, const std::string& save_path)
|
||||
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);
|
||||
|
@ -470,6 +482,8 @@ namespace libtorrent
|
|||
// create the torrent and the data associated with
|
||||
// the checker thread and store it before starting
|
||||
// the thread
|
||||
// TODO: have a queue of checking torrents instead of
|
||||
// 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);
|
||||
|
@ -498,63 +512,8 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
std::pair<torrent_handle::state_t, float> 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);
|
||||
|
||||
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 std::make_pair(invalid_handle, 0.f);
|
||||
return i->second->status();
|
||||
}
|
||||
|
||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v)
|
||||
{
|
||||
v.clear();
|
||||
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);
|
||||
|
||||
for (std::vector<peer_connection*>::const_iterator i = t->begin();
|
||||
i != t->end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* peer = *i;
|
||||
v.push_back(peer_info());
|
||||
peer_info& p = v.back();
|
||||
|
||||
const stat& statistics = peer->statistics();
|
||||
p.down_speed = statistics.download_rate();
|
||||
p.up_speed = statistics.upload_rate();
|
||||
p.id = peer->get_peer_id();
|
||||
p.ip = peer->get_socket()->sender();
|
||||
|
||||
p.flags = 0;
|
||||
if (peer->is_interesting()) p.flags |= peer_info::interesting;
|
||||
if (peer->has_choked()) p.flags |= peer_info::choked;
|
||||
if (peer->is_peer_interested()) p.flags |= peer_info::remote_interested;
|
||||
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;
|
||||
|
||||
p.pieces = peer->get_bitfield();
|
||||
}
|
||||
}
|
||||
|
||||
void torrent_handle::abort()
|
||||
{
|
||||
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;
|
||||
i->second->abort();
|
||||
m_ses = 0;
|
||||
// TODO: join the checking threads!
|
||||
}
|
||||
|
||||
// TODO: document
|
||||
|
|
|
@ -41,10 +41,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
|
||||
#if defined(_MSC_VER) && _MSV_CER < 1300
|
||||
#define for if (false) {} else for
|
||||
|
@ -105,7 +107,7 @@ void libtorrent::piece_file::open(storage* s, int index, open_mode o, int seek_o
|
|||
|
||||
m_file_mode = m;
|
||||
m_file.open(p.native_file_string().c_str(), m_file_mode);
|
||||
std::cout << "opening file: '" << p.native_file_string() << "'\n";
|
||||
// std::cout << "opening file: '" << p.native_file_string() << "'\n";
|
||||
if (m_file.fail())
|
||||
{
|
||||
// TODO: try to recover! create a new file?
|
||||
|
@ -168,7 +170,7 @@ int libtorrent::piece_file::read(char* buf, int size)
|
|||
m_file.close();
|
||||
m_file.clear();
|
||||
m_file.open(path.native_file_string().c_str(), m_file_mode);
|
||||
std::cout << "opening file: '" << path.native_file_string() << "'\n";
|
||||
// std::cout << "opening file: '" << path.native_file_string() << "'\n";
|
||||
if (m_file.fail())
|
||||
{
|
||||
// TODO: try to recover! create a new file?
|
||||
|
@ -221,7 +223,7 @@ void libtorrent::piece_file::write(const char* buf, int size)
|
|||
m_file_offset = 0;
|
||||
m_file.close();
|
||||
m_file.open(path.native_file_string().c_str(), m_file_mode);
|
||||
std::cout << "opening file: '" << path.native_file_string() << "'\n";
|
||||
// std::cout << "opening file: '" << path.native_file_string() << "'\n";
|
||||
if (m_file.fail())
|
||||
{
|
||||
// TODO: try to recover! create a new file?
|
||||
|
@ -294,10 +296,9 @@ bool libtorrent::storage::verify_piece(piece_file& file)
|
|||
assert(read == m_torrent_file->piece_size(index));
|
||||
|
||||
// calculate hash for piece
|
||||
sha1_hash digest;
|
||||
hasher h;
|
||||
h.update(&buffer[0], read);
|
||||
h.final(digest);
|
||||
sha1_hash digest = h.final();
|
||||
|
||||
if (std::equal(digest.begin(), digest.end(), m_torrent_file->hash_for_piece(index).begin()))
|
||||
{
|
||||
|
@ -325,7 +326,13 @@ bool libtorrent::storage::verify_piece(piece_file& file)
|
|||
// allocate files will create all files that are missing
|
||||
// if there are some files that already exists, it checks
|
||||
// that they have the correct filesize
|
||||
void libtorrent::storage::initialize_pieces(torrent* t, const boost::filesystem::path& path)
|
||||
// data is the structure that is shared between the
|
||||
// thread where this function is run in and the
|
||||
// main thread. It is used to communicate progress
|
||||
// and abortion information.
|
||||
void libtorrent::storage::initialize_pieces(torrent* t,
|
||||
const boost::filesystem::path& path,
|
||||
boost::shared_ptr<detail::piece_checker_data> data)
|
||||
{
|
||||
m_save_path = path;
|
||||
m_torrent_file = &t->torrent_file();
|
||||
|
@ -366,13 +373,17 @@ void libtorrent::storage::initialize_pieces(torrent* t, const boost::filesystem:
|
|||
// have
|
||||
bool resume = false;
|
||||
|
||||
unsigned int total_bytes = m_torrent_file->total_size();
|
||||
unsigned int progress = 0;
|
||||
|
||||
// the buffersize of the file writes
|
||||
const int chunksize = 8192;
|
||||
char zeros[chunksize];
|
||||
std::fill(zeros, zeros+chunksize, 0);
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::cout << "allocating files\n";
|
||||
#endif
|
||||
|
||||
// remember which directories we have created, so
|
||||
// we don't have to ask the filesystem all the time
|
||||
|
@ -413,7 +424,7 @@ void libtorrent::storage::initialize_pieces(torrent* t, const boost::filesystem:
|
|||
msg += "\" is in the way.";
|
||||
throw file_allocation_failed(msg.c_str());
|
||||
}
|
||||
std::cout << "creating file: '" << path.native_file_string() << "'\n";
|
||||
// std::cout << "creating file: '" << path.native_file_string() << "'\n";
|
||||
std::ifstream f(path.native_file_string().c_str(), std::ios_base::binary);
|
||||
f.seekg(0, std::ios_base::end);
|
||||
int filesize = f.tellg();
|
||||
|
@ -438,9 +449,19 @@ void libtorrent::storage::initialize_pieces(torrent* t, const boost::filesystem:
|
|||
f.write(zeros, chunksize);
|
||||
// TODO: Check if disk is full
|
||||
left_to_write -= chunksize;
|
||||
progress += chunksize;
|
||||
|
||||
boost::mutex::scoped_lock l(data->mutex);
|
||||
data->progress = static_cast<float>(progress) / total_bytes;
|
||||
if (data->abort) return;
|
||||
}
|
||||
// TODO: Check if disk is full
|
||||
if (left_to_write > 0) f.write(zeros, left_to_write);
|
||||
progress += left_to_write;
|
||||
|
||||
boost::mutex::scoped_lock l(data->mutex);
|
||||
data->progress = static_cast<float>(progress) / total_bytes;
|
||||
if (data->abort) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,21 +469,31 @@ void libtorrent::storage::initialize_pieces(torrent* t, const boost::filesystem:
|
|||
if (resume)
|
||||
{
|
||||
int missing = 0;
|
||||
std::cout << "checking existing files\n";
|
||||
// std::cout << "checking existing files\n";
|
||||
|
||||
int num_pieces = m_torrent_file->num_pieces();
|
||||
|
||||
progress = 0;
|
||||
piece_file f;
|
||||
for (unsigned int i = 0; i < num_pieces; ++i)
|
||||
{
|
||||
f.open(this, i, piece_file::in);
|
||||
if (!verify_piece(f)) missing++;
|
||||
|
||||
std::cout << i+1 << " / " << m_torrent_file->num_pieces() << " missing: " << missing << "\r";
|
||||
// std::cout << i+1 << " / " << m_torrent_file->num_pieces() << " missing: " << missing << "\r";
|
||||
|
||||
progress += m_torrent_file->piece_size(i);
|
||||
boost::mutex::scoped_lock l(data->mutex);
|
||||
data->progress = static_cast<float>(progress) / total_bytes;
|
||||
if (data->abort) return;
|
||||
}
|
||||
std::cout << "\n";
|
||||
// std::cout << "\n";
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::cout << "allocation/checking DONE!\n";
|
||||
#endif
|
||||
|
||||
}
|
||||
/*
|
||||
// reads the piece with the given index from disk
|
||||
|
|
|
@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <cctype>
|
||||
#include <numeric>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
|
@ -142,6 +143,7 @@ namespace libtorrent
|
|||
, m_bytes_uploaded(0)
|
||||
, m_bytes_downloaded(0)
|
||||
, m_torrent_file(torrent_file)
|
||||
, m_unverified_blocks(0)
|
||||
, m_next_request(boost::posix_time::second_clock::local_time())
|
||||
, m_duration(1800)
|
||||
, m_policy(new policy(this))
|
||||
|
@ -401,12 +403,26 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: temporary implementation. Should count the actually
|
||||
// verified pieces and should support the different states
|
||||
// a torrent can be in.
|
||||
std::pair<torrent_handle::state_t, float> torrent::status() const
|
||||
{
|
||||
return std::make_pair(torrent_handle::downloading, 0.f);
|
||||
// TODO: report progress on block-level.
|
||||
// make sure to handle the case where a piece
|
||||
// fails the hash-check
|
||||
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;
|
||||
int blocks_per_piece
|
||||
= m_torrent_file.piece_length() / m_block_size;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/url_handler.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||
namespace std
|
||||
{
|
||||
using ::srand;
|
||||
using ::isprint;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
std::pair<torrent_handle::state_t, float> 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)
|
||||
{
|
||||
boost::mutex::scoped_lock l(d->mutex);
|
||||
return std::make_pair(checking_files, d->progress);
|
||||
}
|
||||
|
||||
return std::make_pair(invalid_handle, 0.f);
|
||||
}
|
||||
|
||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v)
|
||||
{
|
||||
v.clear();
|
||||
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);
|
||||
|
||||
for (std::vector<peer_connection*>::const_iterator i = t->begin();
|
||||
i != t->end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* peer = *i;
|
||||
v.push_back(peer_info());
|
||||
peer_info& p = v.back();
|
||||
|
||||
const stat& statistics = peer->statistics();
|
||||
p.down_speed = statistics.download_rate();
|
||||
p.up_speed = statistics.upload_rate();
|
||||
p.id = peer->get_peer_id();
|
||||
p.ip = peer->get_socket()->sender();
|
||||
|
||||
p.total_download = statistics.total_download();
|
||||
p.total_upload = statistics.total_upload();
|
||||
|
||||
p.flags = 0;
|
||||
if (peer->is_interesting()) p.flags |= peer_info::interesting;
|
||||
if (peer->has_choked()) p.flags |= peer_info::choked;
|
||||
if (peer->is_peer_interested()) p.flags |= peer_info::remote_interested;
|
||||
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;
|
||||
|
||||
p.pieces = peer->get_bitfield();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
m_ses = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -139,7 +139,7 @@ namespace libtorrent
|
|||
bencode(std::back_insert_iterator<std::vector<char> >(buf), info);
|
||||
hasher h;
|
||||
h.update(&buf[0], buf.size());
|
||||
h.final(m_info_hash);
|
||||
m_info_hash = h.final();
|
||||
|
||||
// extract piece length
|
||||
i = info.dict().find("piece length");
|
||||
|
|
Loading…
Reference in New Issue