forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
ec34b1bfdb
commit
1800e63c09
20
Jamfile
20
Jamfile
|
@ -26,13 +26,15 @@ lib torrent
|
|||
;
|
||||
|
||||
|
||||
#exe torrent_test
|
||||
# : src/main.cpp <lib>torrent
|
||||
# $(BOOST_ROOT)/libs/filesystem/build//boost_filesystem
|
||||
# : <include>$(BOOST_ROOT)
|
||||
# <sysinclude>$(BOOST_ROOT)
|
||||
# <include>./
|
||||
# <threading>multi
|
||||
# : debug release
|
||||
# ;
|
||||
exe client_test
|
||||
: examples/client_test.cpp
|
||||
<lib>torrent
|
||||
# <lib>$(BOOST_ROOT)/libs/filesystem/build/boost_filesystem
|
||||
# <dll>$(BOOST_ROOT)/libs/thread/build/boost_thread
|
||||
: <include>$(BOOST_ROOT)
|
||||
<sysinclude>$(BOOST_ROOT)
|
||||
<include>./include
|
||||
<threading>multi
|
||||
: debug release
|
||||
;
|
||||
|
||||
|
|
|
@ -10,6 +10,19 @@
|
|||
<body>
|
||||
|
||||
<h1>libtorrent</h1>
|
||||
|
||||
<table style="margin-left:auto;margin-right:auto" cellpadding="10">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://www.sourceforge.net/projects/libtorrent">sourceforge page</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p>
|
||||
libtorrent is a C++ library that aims to be a good alternative to all the
|
||||
<a href="links.html">other bittorrent implementations</a> around. It is a
|
||||
|
|
|
@ -150,6 +150,14 @@ namespace libtorrent
|
|||
int index;
|
||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||
// TODO: store a hash and a peer_connection reference
|
||||
// for each block. Then if the hash test fails on the
|
||||
// piece, redownload one block from another peer
|
||||
// then the first time, and check the hash again.
|
||||
// also maintain a counter how many times a piece-hash
|
||||
// has been confirmed. Download blocks that hasn't
|
||||
// been confirmed (since they are most probably the
|
||||
// invalid blocks)
|
||||
};
|
||||
|
||||
struct has_index
|
||||
|
@ -172,8 +180,12 @@ namespace libtorrent
|
|||
// that no peer have, the vector at index 1 contains
|
||||
// all pieces that exactly one peer have, index 2 contains
|
||||
// all pieces exactly two peers have and so on.
|
||||
|
||||
std::vector<std::vector<int> > m_piece_info;
|
||||
|
||||
// this vector has the same structure as m_piece_info
|
||||
// but only contains pieces we are currently downloading
|
||||
// they have higher priority than pieces we aren't downloading
|
||||
// during piece picking
|
||||
std::vector<std::vector<int> > m_downloading_piece_info;
|
||||
|
||||
// this maps indices to number of peers that has this piece and
|
||||
|
|
|
@ -72,9 +72,6 @@ namespace libtorrent
|
|||
};
|
||||
|
||||
// wraps access to pieces with a file-like interface
|
||||
// TODO: add functionality for switching piece
|
||||
// that's optimized not to closing the file if the
|
||||
// new piece is in the same file
|
||||
class piece_file
|
||||
{
|
||||
friend class storage;
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace libtorrent
|
|||
struct session_impl;
|
||||
}
|
||||
|
||||
// TODO: each torrent should have a status string that
|
||||
// TODO: each torrent should have a status value that
|
||||
// reflects what's happening to it
|
||||
// TODO: There should be a maximum number of peers that
|
||||
// is maintained (if someone disconnects, try to connect to
|
||||
|
@ -70,6 +70,7 @@ namespace libtorrent
|
|||
// speed than one of the peers currently connected, it will be
|
||||
// replaced to maximize bandwidth usage. It wil also have to
|
||||
// depend on how many and which pieces the peers have.
|
||||
// TODO: In debug mode all pieces that are sent should be checked.
|
||||
|
||||
|
||||
// a torrent is a class that holds information
|
||||
|
@ -119,7 +120,8 @@ namespace libtorrent
|
|||
int bytes_left() const { return m_storage.bytes_left(); }
|
||||
|
||||
// TODO: temporary implementation. Should count the actually
|
||||
// verified pieces
|
||||
// verified pieces and should support the different states
|
||||
// a torrent can be in.
|
||||
float progress() const
|
||||
{
|
||||
return bytes_downloaded() / static_cast<float>(m_torrent_file.total_size());
|
||||
|
@ -238,11 +240,13 @@ namespace libtorrent
|
|||
// blocks when requested
|
||||
int m_block_size;
|
||||
|
||||
// is set to true when the torrent has
|
||||
// been aborted.
|
||||
bool m_abort;
|
||||
|
||||
event_id m_event;
|
||||
|
||||
void parse_response(const entry& e);
|
||||
void parse_response(const entry& e, std::vector<peer>& peer_list);
|
||||
|
||||
// total amount of bytes uploaded, downloaded and
|
||||
// the number of bytes left to be downloaded
|
||||
|
@ -266,9 +270,6 @@ namespace libtorrent
|
|||
std::string m_failed;
|
||||
std::vector<peer_connection*> m_connections;
|
||||
|
||||
// TODO: move to a local function?
|
||||
std::vector<peer> m_peer_list;
|
||||
|
||||
// -----------------------------
|
||||
|
||||
boost::shared_ptr<policy> m_policy;
|
||||
|
|
|
@ -402,9 +402,12 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: we have to let the piece_picker know that
|
||||
// this piece failed the check os it can restore it
|
||||
// we have to let the piece_picker know that
|
||||
// this piece failed the check as it can restore it
|
||||
// and mark it as being interesting for download
|
||||
// TODO: do this more intelligently! and keep track
|
||||
// of how much crap (data that failed hash-check) and
|
||||
// how much redundant data we have downloaded
|
||||
picker.restore_piece(index);
|
||||
}
|
||||
m_torrent->get_policy().piece_finished(*this, index, verified);
|
||||
|
@ -464,8 +467,6 @@ void libtorrent::peer_connection::request_block(piece_block block)
|
|||
|
||||
// TODO: add a timeout to disconnect peer if we don't get any piece messages when
|
||||
// we have requested.
|
||||
// TODO: there must be a way to ask the storage if a given
|
||||
// piece already has some data (and how much). To avoid requesting
|
||||
|
||||
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
|
||||
start_offset +=5;
|
||||
|
@ -685,6 +686,7 @@ void libtorrent::peer_connection::receive_data()
|
|||
{
|
||||
// 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()))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -90,7 +90,6 @@ namespace libtorrent
|
|||
// TODO: random_shuffle
|
||||
}
|
||||
|
||||
// TODO: add a check to make sure m_downloads is intact
|
||||
#ifndef NDEBUG
|
||||
|
||||
void piece_picker::integrity_check(const torrent* t) const
|
||||
|
@ -304,6 +303,13 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
// TODO: since inc_refcount is called
|
||||
// with sequential indices when peers
|
||||
// connect, it will sort the pieces
|
||||
// that is not good. one solution is
|
||||
// to insert the element at a random
|
||||
// index when moving it to another
|
||||
// vector.
|
||||
bool piece_picker::inc_refcount(int i)
|
||||
{
|
||||
assert(i >= 0);
|
||||
|
@ -337,10 +343,6 @@ namespace libtorrent
|
|||
|
||||
if (index == 0xffffff) return;
|
||||
move(m_piece_map[i].downloading, peer_count, index);
|
||||
|
||||
#ifndef NDEBUG
|
||||
integrity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void piece_picker::we_have(int index)
|
||||
|
@ -360,10 +362,8 @@ namespace libtorrent
|
|||
|
||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces, std::vector<piece_block>& interesting_pieces) const
|
||||
{
|
||||
// TODO: modify this!
|
||||
assert(pieces.size() == m_piece_map.size());
|
||||
|
||||
|
||||
// free refers to pieces that are free to download, noone else
|
||||
// is downloading them.
|
||||
// partial is pieces that are partially being downloaded, and
|
||||
|
|
|
@ -71,9 +71,8 @@ namespace
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// compare this peer's bandwidth against the ones downloading
|
||||
// these pieces (busy_pieces)
|
||||
// TODO: compare this peer's bandwidth against the
|
||||
// ones downloading these pieces (busy_pieces)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,9 @@ namespace
|
|||
{
|
||||
peer_id ret;
|
||||
std::srand(std::time(0));
|
||||
// unsigned char fingerprint[] = "h\0\0\0\0\0\0\0\0\0";
|
||||
unsigned char fingerprint[] = "h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
// TODO: add ability to control fingerprint
|
||||
// unsigned char fingerprint[] = "lt.\0\0\0\0\0\0\0";
|
||||
unsigned char fingerprint[] = "lt.\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
const int len = sizeof(fingerprint)-1;
|
||||
std::copy(fingerprint, fingerprint+len, ret.begin());
|
||||
for (unsigned char* i = ret.begin()+len; i != ret.end(); ++i) *i = rand();
|
||||
|
@ -181,7 +182,9 @@ namespace libtorrent
|
|||
// that has been closed. Otherwise we have to wait 2 minutes for their timeout
|
||||
|
||||
// let the readable clients receive data
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = readable_clients.begin(); i != readable_clients.end(); ++i)
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = readable_clients.begin();
|
||||
i != readable_clients.end();
|
||||
++i)
|
||||
{
|
||||
|
||||
// special case for listener socket
|
||||
|
@ -236,7 +239,9 @@ namespace libtorrent
|
|||
// ************************
|
||||
|
||||
// let the writable clients send data
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = writable_clients.begin(); i != writable_clients.end(); ++i)
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = writable_clients.begin();
|
||||
i != writable_clients.end();
|
||||
++i)
|
||||
{
|
||||
connection_map::iterator p = m_connections.find(*i);
|
||||
// the connection may have been disconnected in the receive phase
|
||||
|
@ -269,7 +274,9 @@ namespace libtorrent
|
|||
|
||||
|
||||
// disconnect the one we couldn't connect to
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = error_clients.begin(); i != error_clients.end(); ++i)
|
||||
for (std::vector<boost::shared_ptr<socket> >::iterator i = error_clients.begin();
|
||||
i != error_clients.end();
|
||||
++i)
|
||||
{
|
||||
connection_map::iterator p = m_connections.find(*i);
|
||||
|
||||
|
@ -439,7 +446,7 @@ namespace libtorrent
|
|||
boost::mutex::scoped_lock l(m_impl.m_mutex);
|
||||
|
||||
// is the torrent already active?
|
||||
// TODO: Maybe this should throw?
|
||||
// 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());
|
||||
|
||||
|
|
107
src/torrent.cpp
107
src/torrent.cpp
|
@ -71,7 +71,7 @@ namespace
|
|||
|
||||
int calculate_block_size(const torrent_info& i)
|
||||
{
|
||||
// TODO: if blocks_per_piece > 64 increase block-size
|
||||
// TODO: if blocks_per_piece > 128 increase block-size
|
||||
return 16*1024;
|
||||
}
|
||||
|
||||
|
@ -154,10 +154,63 @@ namespace libtorrent
|
|||
|
||||
void torrent::tracker_response(const entry& e)
|
||||
{
|
||||
std::vector<peer> peer_list;
|
||||
try
|
||||
{
|
||||
// parse the response
|
||||
parse_response(e);
|
||||
parse_response(e, peer_list);
|
||||
|
||||
m_last_working_tracker
|
||||
= m_torrent_file.prioritize_tracker(m_currently_trying_tracker);
|
||||
m_next_request = boost::posix_time::second_clock::local_time()
|
||||
+ boost::posix_time::seconds(m_duration);
|
||||
m_currently_trying_tracker = 0;
|
||||
|
||||
// connect to random peers from the list
|
||||
std::random_shuffle(peer_list.begin(), peer_list.end());
|
||||
|
||||
std::cout << "interval: " << m_duration << "\n";
|
||||
std::cout << "peers:\n";
|
||||
for (std::vector<peer>::const_iterator i = peer_list.begin();
|
||||
i != peer_list.end();
|
||||
++i)
|
||||
{
|
||||
std::cout << " " << std::setfill(' ') << std::setw(16) << i->ip
|
||||
<< " " << std::setw(5) << std::dec << i->port << " ";
|
||||
for (const unsigned char* j = i->id.begin();
|
||||
j != i->id.end();
|
||||
++j)
|
||||
{
|
||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<unsigned int>(*j);
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
std::cout << std::dec << std::setfill(' ');
|
||||
|
||||
|
||||
// for each of the peers we got from the tracker
|
||||
for (std::vector<peer>::iterator i = peer_list.begin();
|
||||
i != peer_list.end();
|
||||
++i)
|
||||
{
|
||||
// don't make connections to ourself
|
||||
if (i->id == m_ses->get_peer_id())
|
||||
continue;
|
||||
|
||||
address a(i->ip, i->port);
|
||||
|
||||
// if we aleady have a connection to the person, don't make another one
|
||||
if (std::find_if(m_ses->m_connections.begin(),
|
||||
m_ses->m_connections.end(),
|
||||
find_peer(i->id, this)) != m_ses->m_connections.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_policy->peer_from_tracker(a, i->id);
|
||||
}
|
||||
|
||||
}
|
||||
catch(type_error& e)
|
||||
{
|
||||
|
@ -168,30 +221,6 @@ namespace libtorrent
|
|||
tracker_request_error(e.what());
|
||||
}
|
||||
|
||||
m_last_working_tracker = m_torrent_file.prioritize_tracker(m_currently_trying_tracker);
|
||||
m_next_request = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(m_duration);
|
||||
m_currently_trying_tracker = 0;
|
||||
|
||||
// connect to random peers from the list
|
||||
std::random_shuffle(m_peer_list.begin(), m_peer_list.end());
|
||||
|
||||
print(std::cout);
|
||||
|
||||
// for each of the peers we got from the tracker
|
||||
for (std::vector<peer>::iterator i = m_peer_list.begin(); i != m_peer_list.end(); ++i)
|
||||
{
|
||||
// don't make connections to ourself
|
||||
if (i->id == m_ses->get_peer_id())
|
||||
continue;
|
||||
|
||||
address a(i->ip, i->port);
|
||||
|
||||
// if we aleady have a connection to the person, don't make another one
|
||||
if (std::find_if(m_ses->m_connections.begin(), m_ses->m_connections.end(), find_peer(i->id, this)) != m_ses->m_connections.end())
|
||||
continue;
|
||||
|
||||
m_policy->peer_from_tracker(a, i->id);
|
||||
}
|
||||
}
|
||||
|
||||
int torrent::num_connections(const peer_id& id) const
|
||||
|
@ -223,7 +252,6 @@ namespace libtorrent
|
|||
m_next_request = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(m_duration);
|
||||
|
||||
std::vector<char> buffer;
|
||||
// TODO: temporary! support multi-tracker
|
||||
std::string request = m_torrent_file.trackers()[m_currently_trying_tracker].url;
|
||||
|
||||
request += "?info_hash=";
|
||||
|
@ -255,7 +283,7 @@ namespace libtorrent
|
|||
return request;
|
||||
}
|
||||
|
||||
void torrent::parse_response(const entry& e)
|
||||
void torrent::parse_response(const entry& e, std::vector<peer>& peer_list)
|
||||
{
|
||||
entry::dictionary_type::const_iterator i = e.dict().find("failure reason");
|
||||
if (i != e.dict().end())
|
||||
|
@ -272,15 +300,14 @@ namespace libtorrent
|
|||
i = msg.find("peers");
|
||||
if (i == msg.end()) throw std::runtime_error("invalid response from tracker");
|
||||
|
||||
m_peer_list.clear();
|
||||
peer_list.clear();
|
||||
|
||||
const entry::list_type& peer_list = i->second.list();
|
||||
for(entry::list_type::const_iterator i = peer_list.begin(); i != peer_list.end(); ++i)
|
||||
const entry::list_type& l = i->second.list();
|
||||
for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
|
||||
{
|
||||
peer p = extract_peer_info(*i);
|
||||
m_peer_list.push_back(p);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void torrent::remove_peer(peer_connection* p)
|
||||
|
@ -328,20 +355,6 @@ namespace libtorrent
|
|||
std::cout << "connecting to: " << a.as_string() << ":" << a.port() << "\n";
|
||||
}
|
||||
|
||||
void torrent::print(std::ostream& os) const
|
||||
{
|
||||
os << "interval: " << m_duration << "\n";
|
||||
os << "peers:\n";
|
||||
for (std::vector<peer>::const_iterator i = m_peer_list.begin(); i != m_peer_list.end(); ++i)
|
||||
{
|
||||
os << " " << std::setfill(' ') << std::setw(16) << i->ip << " " << std::setw(5) << std::dec << i->port << " ";
|
||||
for (const unsigned char* j = i->id.begin(); j != i->id.end(); ++j)
|
||||
os << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*j);
|
||||
os << "\n";
|
||||
}
|
||||
os << std::dec << std::setfill(' ');
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
logger* torrent::spawn_logger(const char* title)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue