queued_for_checking
@@ -550,6 +582,52 @@ current task is in the state member, it will be one of the following:
uploaded to all peers, accumulated.
+get_download_queue()
+
+
+get_download_queue() takes a non-const reference to a vector which it will fill
+information about pieces that are partially downloaded or not downloaded at all but partially
+requested. The entry in the vector (partial_piece_info) looks like this:
+
+
+
+struct partial_piece_info
+{
+ enum { max_blocks_per_piece = implementation-defined };
+ int piece_index;
+ int blocks_in_piece;
+ std::bitset<max_blocks_per_piece> requested_blocks;
+ std::bitset<max_blocks_per_piece> finished_blocks;
+ peer_id peer[max_blocks_per_piece];
+ int num_downloads[max_blocks_per_piece];
+};
+
+
+
+piece_index is the index of the piece in question. blocks_in_piece is the
+number of blocks in this particular piece. This number will be the same for most pieces, but
+the last piece may have fewer blocks than the standard pieces.
+
+
+
+requested_blocks is a bitset with one bit per block in the piece. If a bit is set, it
+means that that block has been requested, but not necessarily fully downloaded yet. To know
+from whom the block has been requested, have a look in the peer array. The bit-index
+in the requested_blocks and finished_blocks correspons to the array-index into
+peers and num_downloads. The array of peers is contains the id of the
+peer the piece was requested from. If a piece hasn't been requested (the bit in
+requested_blocks is not set) the peer array entry will be undefined.
+
+
+
+The finished_blocks is a bitset where each bit says if the block is fully downloaded
+or not. And the num_downloads array says how many times that block has been downloaded.
+When a piece fails a hash verification, single blocks may be redownloaded to see if the hash teast
+may pass then.
+
+
+get_peer_info()
+
get_peer_info() takes a reference to a vector that will be cleared and filled
with one entry for each peer connected to this torrent. Each entry contains information about
@@ -720,6 +798,16 @@ The sha1-algorithm used was implemented by Steve Reid and released as public dom
For more info, see src/sha1.c.
+Feedback
+
+
+There's a mailing list.
+
+
+
+You can usually find me as hydri in #btports @ irc.freenode.net.
+
+
Credits
diff --git a/examples/client_test.cpp b/examples/client_test.cpp
index 73f0f16be..8d24534bd 100755
--- a/examples/client_test.cpp
+++ b/examples/client_test.cpp
@@ -35,12 +35,15 @@ POSSIBILITY OF SUCH DAMAGE.
#include
#include
+#include
+
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/http_settings.hpp"
#ifdef WIN32
+#include
#include
bool sleep_and_input(char* c)
@@ -54,6 +57,21 @@ bool sleep_and_input(char* c)
return false;
};
+void set_cursor(int x, int y)
+{
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ COORD c = {x, y};
+ SetConsoleCursorPosition(h, c);
+}
+
+void clear()
+{
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ COORD c = {0, 0};
+ DWORD n;
+ FillConsoleOutputCharacter(h, ' ', 80 * 50, c, &n);
+}
+
#else
#include
@@ -155,6 +173,7 @@ int main(int argc, char* argv[])
}
std::vector peers;
+ std::vector queue;
for (;;)
{
@@ -164,6 +183,8 @@ int main(int argc, char* argv[])
if (c == 'q') break;
}
+ clear();
+ set_cursor(0, 0);
for (std::vector::iterator i = handles.begin();
i != handles.end();
++i)
@@ -173,21 +194,19 @@ int main(int argc, char* argv[])
switch(s.state)
{
case torrent_status::queued_for_checking:
- std::cout << "queued for checking: ";
+ std::cout << "queued ";
break;
case torrent_status::checking_files:
- std::cout << "checking files: ";
+ std::cout << "checking ";
break;
case torrent_status::downloading:
- std::cout << "downloading: ";
+ std::cout << "dloading ";
break;
case torrent_status::seeding:
- std::cout << "seeding: ";
+ std::cout << "seeding ";
break;
};
- std::cout << s.progress*100 << "% ";
-
// calculate download and upload speeds
i->get_peer_info(peers);
float down = 0.f;
@@ -205,14 +224,35 @@ int main(int argc, char* argv[])
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:("
+/*
+ std::cout << boost::format("%f%% p:%d d:(%s) %s/s u:(%s) %s/s\n")
+ % (s.progress*100)
+ % num_peers
+ % add_suffix(total_down)
+ % add_suffix(down)
+ % add_suffix(total_up)
+ % add_suffix(up);
+*/
+ std::cout << (s.progress*100) << "% p:" << num_peers << " d:("
+ << add_suffix(total_down) << ") " << add_suffix(down) << "/s u:("
<< add_suffix(total_up) << ") " << add_suffix(up) << "/s\n";
+
+ i->get_download_queue(queue);
+ for (std::vector::iterator i = queue.begin();
+ i != queue.end();
+ ++i)
+ {
+ std::cout << i->piece_index << ": ";
+ for (int j = 0; j < i->blocks_in_piece; ++j)
+ {
+ if (i->finished_blocks[j]) std::cout << "#";
+ else if (i->requested_blocks[j]) std::cout << "-";
+ else std::cout << ".";
+ }
+ std::cout << "\n";
+ }
+ std::cout << "___________________________________\n";
}
- std::cout << "----\n";
}
}
catch (std::exception& e)
diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp
deleted file mode 100755
index 109f02d6f..000000000
--- a/include/libtorrent/config.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-
-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.
-
-*/
-
-
-#ifndef TORRENT_CONFIG_HPP_INCLUDED
-#define TORRENT_CONFIG_HPP_INCLUDED
-
-#if defined(_WINDOWS)
- #if defined(_USRDLL)
- #define TORRENT_EXPORT __declspec(dllexport)
- #else
- #define TORRENT_EXPORT __declspec(dllimport)
- #endif
-#else
-
- #define TORRENT_EXPORT
-
-#endif
-
-
-#endif
diff --git a/include/libtorrent/peer_id.hpp b/include/libtorrent/peer_id.hpp
index 43776dbc2..c9c15a616 100755
--- a/include/libtorrent/peer_id.hpp
+++ b/include/libtorrent/peer_id.hpp
@@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_PEER_ID_HPP_INCLUDED
#define TORRENT_PEER_ID_HPP_INCLUDED
+#include
+#include
namespace libtorrent
{
@@ -63,11 +65,14 @@ namespace libtorrent
return false;
}
- const unsigned char* begin() const { return m_number; }
- const unsigned char* end() const { return m_number+number_size; }
+ typedef const unsigned char* const_iterator;
+ typedef unsigned char* iterator;
- unsigned char* begin() { return m_number; }
- unsigned char* end() { return m_number+number_size; }
+ const_iterator begin() const { return m_number; }
+ const_iterator end() const { return m_number+number_size; }
+
+ iterator begin() { return m_number; }
+ iterator end() { return m_number+number_size; }
private:
@@ -78,6 +83,19 @@ namespace libtorrent
typedef big_number peer_id;
typedef big_number sha1_hash;
+ inline std::ostream& operator<<(std::ostream& os, const big_number& peer)
+ {
+ for (big_number::const_iterator i = peer.begin();
+ i != peer.end();
+ ++i)
+ {
+ os << std::hex << std::setw(2) << std::setfill('0')
+ << static_cast(*i);
+ }
+ os << std::dec << std::cout << std::setfill(' ');
+ return os;
+ }
+
}
#endif // TORRENT_PEER_ID_HPP_INCLUDED
diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp
index 7828c1bde..e368b2489 100755
--- a/include/libtorrent/piece_picker.hpp
+++ b/include/libtorrent/piece_picker.hpp
@@ -37,6 +37,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include
#include
+#include "libtorrent/peer_id.hpp"
+
namespace libtorrent
{
@@ -60,6 +62,37 @@ namespace libtorrent
enum { max_blocks_per_piece = 128 };
+ struct block_info
+ {
+ block_info(): num_downloads(0) {}
+ // the peer this block was requested or
+ // downloaded from
+ peer_id peer;
+ // the number of times this block has been downloaded
+ int num_downloads;
+ };
+
+ struct downloading_piece
+ {
+ int index;
+ // each bit represents a block in the piece
+ // set to one if the block has been requested
+ std::bitset requested_blocks;
+ // the bit is set to one if the block has been acquired
+ std::bitset finished_blocks;
+ // info about each block
+ block_info info[max_blocks_per_piece];
+
+ // 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)
+ };
+
piece_picker(int blocks_per_piece,
int total_num_blocks);
@@ -92,7 +125,8 @@ namespace libtorrent
// itself, by using the mark_as_downloading() member function.
// THIS IS DONE BY THE peer_connection::request_piece() MEMBER FUNCTION!
void pick_pieces(const std::vector& pieces,
- std::vector& interesting_blocks) const;
+ std::vector& interesting_blocks,
+ int num_pieces) const;
// returns true if any client is currently downloading this
// piece-block, or if it's queued for downloading by some client
@@ -100,11 +134,11 @@ namespace libtorrent
bool is_downloading(piece_block block) const;
// marks this piece-block as queued for downloading
- void mark_as_downloading(piece_block block);
+ void mark_as_downloading(piece_block block, const peer_id& peer);
void mark_as_finished(piece_block block);
// if a piece had a hash-failure, it must be restured and
- // made available fro redownloading
+ // made available for redownloading
void restore_piece(int index);
// clears the given piece's download flag
@@ -113,9 +147,17 @@ namespace libtorrent
bool is_piece_finished(int index) const;
+ // returns the number of blocks there is in the goven piece
int blocks_in_piece(int index) const;
+
+ // the number of downloaded blocks that hasn't passed
+ // the hash-check yet
int unverified_blocks() const;
+ void get_downloaders(std::vector& d, int index);
+ const std::vector& get_download_queue() const
+ { return m_downloads; }
+
#ifndef NDEBUG
// used in debug mode
void integrity_check(const torrent* t = 0) const;
@@ -147,20 +189,7 @@ namespace libtorrent
};
- struct downloading_piece
- {
- int index;
- std::bitset requested_blocks;
- std::bitset 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
{
@@ -173,9 +202,10 @@ namespace libtorrent
void move(bool downloading, int vec_index, int elem_index);
void remove(bool downloading, int vec_index, int elem_index);
- bool add_interesting_blocks(const std::vector& piece_list,
+ int add_interesting_blocks(const std::vector& piece_list,
const std::vector& pieces,
- std::vector& interesting_pieces) const;
+ std::vector& interesting_pieces,
+ int num_blocks) const;
// this vector contains all pieces we don't have.
// in the first entry (index 0) is a vector of all pieces
diff --git a/include/libtorrent/socket.hpp b/include/libtorrent/socket.hpp
index 56d2039bf..3649e7582 100755
--- a/include/libtorrent/socket.hpp
+++ b/include/libtorrent/socket.hpp
@@ -238,12 +238,21 @@ namespace libtorrent
void monitor_readability(boost::shared_ptr s) { m_readable.push_back(s); }
void monitor_writability(boost::shared_ptr s) { m_writable.push_back(s); }
void monitor_errors(boost::shared_ptr s) { m_error.push_back(s); }
-
+/*
void clear_readable() { m_readable.clear(); }
void clear_writable() { m_writable.clear(); }
-
+*/
void remove(boost::shared_ptr s);
+ void remove_writable(boost::shared_ptr s)
+ { m_writable.erase(std::find(m_writable.begin(), m_writable.end(), s)); }
+
+ bool is_writability_monitored(boost::shared_ptr s)
+ {
+ return std::find(m_writable.begin(), m_writable.end(), s)
+ != m_writable.end();
+ }
+
void wait(int timeout
, std::vector >& readable
, std::vector >& writable
diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp
index ec6c8ee37..a20e2f7c6 100755
--- a/include/libtorrent/torrent_handle.hpp
+++ b/include/libtorrent/torrent_handle.hpp
@@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_id.hpp"
#include "libtorrent/peer_info.hpp"
+#include "libtorrent/piece_picker.hpp"
namespace libtorrent
@@ -47,6 +48,11 @@ namespace libtorrent
struct checker_impl;
}
+ struct duplicate_torrent: std::exception
+ {
+ virtual const char* what() const { return "torrent already exists in session"; }
+ };
+
struct torrent_status
{
enum state_t
@@ -54,7 +60,6 @@ namespace libtorrent
invalid_handle,
queued_for_checking,
checking_files,
- connecting_to_tracker,
downloading,
seeding
};
@@ -65,6 +70,17 @@ namespace libtorrent
std::size_t total_upload;
};
+ struct partial_piece_info
+ {
+ enum { max_blocks_per_piece = piece_picker::max_blocks_per_piece };
+ int piece_index;
+ int blocks_in_piece;
+ std::bitset requested_blocks;
+ std::bitset finished_blocks;
+ peer_id peer[max_blocks_per_piece];
+ int num_downloads[max_blocks_per_piece];
+ };
+
struct torrent_handle
{
friend class session;
@@ -76,6 +92,8 @@ namespace libtorrent
torrent_status status() const;
+ void get_download_queue(std::vector& queue) const;
+
// TODO: add a 'time to next announce' query.
private:
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index 3db5d4a86..e75926633 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -399,12 +399,21 @@ bool libtorrent::peer_connection::dispatch_message()
}
else
{
+#ifndef NDEBUG
+ std::cout << "hash-test failed. Some of these peers sent invalid data:\n";
+ std::vector downloaders;
+ picker.get_downloaders(downloaders, index);
+ std::copy(downloaders.begin(), downloaders.end(), std::ostream_iterator(std::cout, "\n"));
+#endif
// 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
+ // if some clients has sent more than one piece
+ // start with redownloading the pieces that the client
+ // that has sent the least number of pieces
picker.restore_piece(index);
}
m_torrent->get_policy().piece_finished(*this, index, verified);
@@ -446,7 +455,7 @@ void libtorrent::peer_connection::request_block(piece_block block)
assert(block.piece_index < m_torrent->torrent_file().num_pieces());
assert(!m_torrent->picker().is_downloading(block));
- m_torrent->picker().mark_as_downloading(block);
+ m_torrent->picker().mark_as_downloading(block, m_peer_id);
m_download_queue.push_back(block);
@@ -785,6 +794,8 @@ bool libtorrent::peer_connection::has_data() const throw()
// throws exception when the client should be disconnected
void libtorrent::peer_connection::send_data()
{
+ assert(has_data());
+
// only add new piece-chunks if the send buffer is empty
// otherwise there will be no end to how large it will be!
if (!m_requests.empty() && m_send_buffer.empty() && m_peer_interested && !m_choked)
diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp
index 4570b34b1..d24e5d7ec 100755
--- a/src/piece_picker.cpp
+++ b/src/piece_picker.cpp
@@ -360,10 +360,16 @@ namespace libtorrent
#endif
}
- void piece_picker::pick_pieces(const std::vector& pieces, std::vector& interesting_pieces) const
+ void piece_picker::pick_pieces(const std::vector& pieces,
+ std::vector& interesting_pieces,
+ int num_blocks) const
{
assert(pieces.size() == m_piece_map.size());
+#ifndef NDEBUG
+ integrity_check();
+#endif
+
// free refers to pieces that are free to download, noone else
// is downloading them.
// partial is pieces that are partially being downloaded, and
@@ -378,10 +384,8 @@ namespace libtorrent
{
for (int i = 0; i < 2; ++i)
{
- if (add_interesting_blocks(*partial, pieces, interesting_pieces))
- {
- return;
- }
+ num_blocks = add_interesting_blocks(*partial, pieces, interesting_pieces, num_blocks);
+ if (num_blocks == 0) return;
++partial;
if (partial == m_downloading_piece_info.end()) break;
}
@@ -389,18 +393,17 @@ namespace libtorrent
if (free != m_piece_info.end())
{
- if (add_interesting_blocks(*free, pieces, interesting_pieces))
- {
- return;
- }
+ num_blocks = add_interesting_blocks(*free, pieces, interesting_pieces, num_blocks);
+ if (num_blocks == 0) return;
++free;
}
}
}
- bool piece_picker::add_interesting_blocks(const std::vector& piece_list,
+ int piece_picker::add_interesting_blocks(const std::vector& piece_list,
const std::vector& pieces,
- std::vector& interesting_blocks) const
+ std::vector& interesting_blocks,
+ int num_blocks) const
{
for (std::vector::const_iterator i = piece_list.begin();
@@ -418,15 +421,20 @@ namespace libtorrent
if (m_piece_map[*i].downloading == 0)
{
- interesting_blocks.push_back(piece_block(*i, 0));
- return true; // we have found a piece that's free to download
+ int piece_blocks = std::min(blocks_in_piece(*i), num_blocks);
+ for (int j = 0; j < piece_blocks; ++j)
+ {
+ interesting_blocks.push_back(piece_block(*i, 0));
+ }
+ num_blocks -= piece_blocks;
+ if (num_blocks == 0) return num_blocks;
+ continue;
}
// calculate the number of blocks in this
// piece. It's always m_blocks_per_piece, except
// in the last piece.
- int num_blocks_in_piece
- = (*i == m_piece_map.size()-1)?m_blocks_in_last_piece:m_blocks_per_piece;
+ int num_blocks_in_piece = blocks_in_piece(*i);
std::vector::const_iterator p
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
@@ -436,10 +444,14 @@ namespace libtorrent
{
interesting_blocks.push_back(piece_block(*i, j));
if (p->requested_blocks[j] == 0)
- return true; // we have found a piece that's free to download
+ {
+ // we have found a piece that's free to download
+ num_blocks--;
+ if (num_blocks == 0) return num_blocks;
+ }
}
}
- return false;
+ return num_blocks;
}
bool piece_picker::is_piece_finished(int index) const
@@ -471,7 +483,7 @@ namespace libtorrent
return i->requested_blocks[block.block_index];
}
- void piece_picker::mark_as_downloading(piece_block block)
+ void piece_picker::mark_as_downloading(piece_block block, const peer_id& peer)
{
#ifndef NDEBUG
integrity_check();
@@ -488,6 +500,7 @@ namespace libtorrent
downloading_piece dp;
dp.index = block.piece_index;
dp.requested_blocks[block.block_index] = 1;
+ dp.info[block.block_index].peer = peer;
m_downloads.push_back(dp);
}
else
@@ -496,6 +509,7 @@ namespace libtorrent
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
assert(i->requested_blocks[block.block_index] == 0);
+ i->info[block.block_index].peer = peer;
i->requested_blocks[block.block_index] = 1;
}
#ifndef NDEBUG
@@ -518,11 +532,24 @@ namespace libtorrent
assert(i != m_downloads.end());
assert(i->requested_blocks[block.block_index] == 1);
i->finished_blocks[block.block_index] = 1;
+ i->info[block.block_index].num_downloads++;
#ifndef NDEBUG
integrity_check();
#endif
}
+ void piece_picker::get_downloaders(std::vector& d, int index)
+ {
+ std::vector::iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
+ assert(i != m_downloads.end());
+
+ d.clear();
+ for (int j = 0; j < blocks_in_piece(index); ++j)
+ {
+ d.push_back(i->info[j].peer);
+ }
+ }
void piece_picker::abort_download(piece_block block)
{
diff --git a/src/policy.cpp b/src/policy.cpp
index 0b8f36dbd..130646dd5 100755
--- a/src/policy.cpp
+++ b/src/policy.cpp
@@ -39,13 +39,30 @@ POSSIBILITY OF SUCH DAMAGE.
namespace
{
+ enum
+ {
+ // we try to maintain 4 requested blocks in the download
+ // queue
+ request_queue = 4
+ };
+
+
using namespace libtorrent;
void request_a_block(torrent& t, peer_connection& c)
{
piece_picker& p = t.picker();
std::vector interesting_pieces;
interesting_pieces.reserve(100);
- p.pick_pieces(c.get_bitfield(), interesting_pieces);
+
+ int num_requests = request_queue - c.download_queue().size();
+ if (num_requests <= 0) num_requests = 1;
+
+ // picks the interesting pieces from this peer
+ // the integer is the number of pieces that
+ // should be guaranteed to be available for download
+ // (if this number is too big, too many pieces are
+ // picked and cpu-time is wasted)
+ p.pick_pieces(c.get_bitfield(), interesting_pieces, num_requests);
// this vector is filled with the interestin pieces
// that some other peer is currently downloading
@@ -68,7 +85,8 @@ namespace
// ok, we found a piece that's not being downloaded
// by somebody else. request it from this peer
c.request_block(*i);
- return;
+ num_requests++;
+ if (num_requests >= request_queue) return;
}
// TODO: compare this peer's bandwidth against the
diff --git a/src/session.cpp b/src/session.cpp
index 11910a636..ab2fa41d3 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -182,6 +182,8 @@ namespace libtorrent
#if defined(TORRENT_VERBOSE_LOGGING)
m_logger = create_log("main session");
#endif
+ try
+ {
boost::shared_ptr listener(new socket(socket::tcp, false));
int max_port = m_listen_port + 9;
@@ -233,6 +235,11 @@ namespace libtorrent
#endif
for(;;)
{
+#ifndef NDEBUG
+ std::clock_t time__ = std::clock();
+#endif
+
+
// if nothing happens within 500000 microseconds (0.5 seconds)
// do the loop anyway to check if anything else has changed
// (*m_logger) << "sleeping\n";
@@ -243,6 +250,10 @@ namespace libtorrent
num_loops++;
#endif
+
+ assert(readable_clients.size() + writable_clients.size() + error_clients.size() > 0
+ || (std::clock() - time__) > CLOCKS_PER_SEC / 3);
+
// +1 for the listen socket
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
@@ -262,6 +273,7 @@ namespace libtorrent
break;
}
+
// ************************
// RECEIVE SOCKETS
// ************************
@@ -297,7 +309,6 @@ namespace libtorrent
continue;
}
-
connection_map::iterator p = m_connections.find(*i);
if(p == m_connections.end())
{
@@ -321,7 +332,6 @@ namespace libtorrent
}
-
// ************************
// SEND SOCKETS
// ************************
@@ -342,8 +352,15 @@ namespace libtorrent
{
try
{
+ assert(m_selector.is_writability_monitored(p->first));
+ assert(p->second->has_data());
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
p->second->send_data();
+ // if the peer doesn't have
+ // any data left to send, remove it
+ // from the writabilty monitor
+ if (!p->second->has_data())
+ m_selector.remove_writable(p->first);
}
catch(network_error&)
{
@@ -374,16 +391,27 @@ namespace libtorrent
if (p != m_connections.end()) m_connections.erase(p);
}
+#ifndef NDEBUG
+ for (connection_map::iterator i = m_connections.begin();
+ i != m_connections.end();
+ ++i)
+ {
+ if (m_selector.is_writability_monitored(i->first))
+ assert(i->second->has_data());
+ }
+#endif
+
// clear all writablility monitors and add
// the ones who still has data to send
- m_selector.clear_writable();
+/* m_selector.clear_writable();
// ************************
// BUILD WRITER LIST
// ************************
+ // TODO: REWRITE THIS! DON'T GO THROUGH THIS LOOP EVERY TIME!
// loop over all clients and purge the ones that has timed out
// and check if they have pending data to be sent
@@ -411,7 +439,7 @@ namespace libtorrent
}
}
}
-
+*/
// (*m_logger) << "time: " << std::clock()-timer << "\n";
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
if (d.seconds() < 1) continue;
@@ -422,18 +450,41 @@ namespace libtorrent
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
// ************************
+
#ifdef TORRENT_DEBUG_SOCKETS
std::cout << "\nloops: " << num_loops << "\n";
- assert(loops < 1300);
+ if (num_loops > 1300)
+ {
+ int i = 0;
+ }
num_loops = 0;
#endif
// do the second_tick() on each connection
// this will update their statistics (download and upload speeds)
- for (connection_map::iterator i = m_connections.begin(); i != m_connections.end(); ++i)
+ // also purge sockets that have timed out
+ // and keep sockets open by keeping them alive.
+ for (connection_map::iterator i = m_connections.begin();
+ i != m_connections.end();)
{
i->second->second_tick();
+
+ connection_map::iterator j = i;
+ ++i;
+ // if this socket has timed out
+ // close it.
+ if (j->second->has_timed_out())
+ {
+ m_selector.remove(j->first);
+ m_connections.erase(j);
+ continue;
+ }
+
+ j->second->keep_alive();
+
+ if (j->second->has_data() && !m_selector.is_writability_monitored(j->first))
+ m_selector.monitor_writability(j->first);
}
// check each torrent for abortion or
@@ -484,6 +535,17 @@ namespace libtorrent
t.nsec += 1000000;
boost::thread::sleep(t);
}
+ }
+ catch(const std::exception& e)
+ {
+ std::cout << e.what() << "\n";
+ }
+ catch(...)
+ {
+ std::cout << "error\n";
+ }
+
+
}
// the return value from this function is valid only as long as the
@@ -498,6 +560,7 @@ namespace libtorrent
}
+ // if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent(const torrent_info& ti,
const std::string& save_path)
{
@@ -507,9 +570,8 @@ namespace libtorrent
boost::mutex::scoped_lock l(m_impl.m_mutex);
// 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());
+ throw duplicate_torrent();
}
{
@@ -517,9 +579,8 @@ namespace libtorrent
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());
+ throw duplicate_torrent();
}
// create the torrent and the data associated with
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 1b41efec2..109cd76f1 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -187,9 +187,9 @@ namespace libtorrent
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< static_cast(*j);
}
- std::cout << " " << extract_fingerprint(i->id) << "\n";
+ std::cout << std::dec << " " << extract_fingerprint(i->id) << "\n";
}
- std::cout << std::dec << std::setfill(' ');
+ std::cout << std::setfill(' ');
// for each of the peers we got from the tracker
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index b64cf0251..9bc1a25d3 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -143,11 +143,44 @@ namespace libtorrent
}
}
+ void torrent_handle::get_download_queue(std::vector& queue) const
+ {
+ queue.clear();
+
+ if (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) return;
+
+ const piece_picker& p = t->picker();
+
+ const std::vector& q
+ = p.get_download_queue();
+
+ for (std::vector::const_iterator i
+ = q.begin();
+ i != q.end();
+ ++i)
+ {
+ partial_piece_info pi;
+ pi.finished_blocks = i->finished_blocks;
+ pi.requested_blocks = i->requested_blocks;
+ for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j)
+ {
+ pi.peer[j] = i->info[j].peer;
+ pi.num_downloads[j] = i->info[j].num_downloads;
+ }
+ pi.piece_index = i->index;
+ pi.blocks_in_piece = p.blocks_in_piece(i->index);
+ queue.push_back(pi);
+ }
+ }
+
void torrent_handle::abort()
{
if (m_ses == 0) return;
-
{
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
|