Increased performance. Fixed a bug. Extended torrent_handle interface.
This commit is contained in:
parent
c9bfb8aa36
commit
8b61436561
110
docs/index.html
110
docs/index.html
|
@ -53,6 +53,23 @@ The current state includes the following features:
|
||||||
<li>gzipped tracker-responses
|
<li>gzipped tracker-responses
|
||||||
<li>piece picking on block-level (as opposed to piece-level) like in
|
<li>piece picking on block-level (as opposed to piece-level) like in
|
||||||
<a href="http://azureus.sourceforge.net/">Azureus</a>
|
<a href="http://azureus.sourceforge.net/">Azureus</a>
|
||||||
|
<li>queues torrents for file check, instead of checking all of them in parallel.
|
||||||
|
<li>uses separate threads for checking files and for main downloader, with a fool-proof
|
||||||
|
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Functions that are yet to be implemented:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>optimistic unchoke
|
||||||
|
<li>upload speed cap
|
||||||
|
<li>Snubbing
|
||||||
|
<li>end game mode
|
||||||
|
<li>new allocation model
|
||||||
|
<li>fast resume
|
||||||
|
<li>file-level piece priority
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -153,6 +170,12 @@ want to save the files. The <tt>save_path</tt> will be prepended to the director
|
||||||
structure in the torrent-file.
|
structure in the torrent-file.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If the torrent you are trying to add already exists in the session (is either queued
|
||||||
|
for checking, being checked or downloading) <tt>add_torrent()</tt> will throw
|
||||||
|
<tt>duplicate_torrent</tt> which derives from <tt>std::exception</tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>fingerprint</tt> is a short string that will be used in the peer_id to
|
<tt>fingerprint</tt> is a short string that will be used in the peer_id to
|
||||||
identify the client. If the string is longer than 7 characters it will
|
identify the client. If the string is longer than 7 characters it will
|
||||||
|
@ -453,28 +476,29 @@ Its declaration looks like this:
|
||||||
struct torrent_handle
|
struct torrent_handle
|
||||||
{
|
{
|
||||||
torrent_handle();
|
torrent_handle();
|
||||||
|
|
||||||
void get_peer_info(std::vector<peer_info>& v);
|
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
enum state_t
|
|
||||||
{
|
|
||||||
checking_files,
|
|
||||||
connecting_to_tracker,
|
|
||||||
downloading,
|
|
||||||
seeding
|
|
||||||
};
|
|
||||||
|
|
||||||
torrent_status status() const;
|
torrent_status status() const;
|
||||||
|
void get_download_queue(std::vector<partial_piece_info>& queue);
|
||||||
|
void get_peer_info(std::vector<peer_info>& v);
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The default constructor will initialize the handle to an invalid state. Which means you cannot
|
||||||
|
perform any operation on it, unless you first assign it a valid handle. If you try to perform
|
||||||
|
any operation they will simply return.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>abort()</tt> will close all peer connections associated with this torrent and tell
|
<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
|
the tracker that we've stopped participating in the swarm. This handle will become invalid
|
||||||
shortly after this call has been made.
|
shortly after this call has been made.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>status()</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>status()</tt> will return a structure with information about the status of this
|
<tt>status()</tt> will return a structure with information about the status of this
|
||||||
torrent. It contains the following fields:
|
torrent. It contains the following fields:
|
||||||
|
@ -488,7 +512,6 @@ struct torrent_status
|
||||||
invalid_handle,
|
invalid_handle,
|
||||||
queued_for_checking,
|
queued_for_checking,
|
||||||
checking_files,
|
checking_files,
|
||||||
connecting_to_tracker,
|
|
||||||
downloading,
|
downloading,
|
||||||
seeding
|
seeding
|
||||||
};
|
};
|
||||||
|
@ -507,6 +530,15 @@ current task is in the <tt>state</tt> member, it will be one of the following:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<tt>invalid_handle</tt>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
This will be the state if you called status on an uninitialized handle (a
|
||||||
|
handle that was constructed with the default constructor).
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<tt>queued_for_checking</tt>
|
<tt>queued_for_checking</tt>
|
||||||
|
@ -550,6 +582,52 @@ current task is in the <tt>state</tt> member, it will be one of the following:
|
||||||
uploaded to all peers, accumulated.
|
uploaded to all peers, accumulated.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>get_download_queue()</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>get_download_queue()</tt> 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 (<tt>partial_piece_info</tt>) looks like this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
struct partial_piece_info
|
||||||
|
{
|
||||||
|
enum { max_blocks_per_piece = <i>implementation-defined</i> };
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>piece_index</tt> is the index of the piece in question. <tt>blocks_in_piece</tt> 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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>requested_blocks</tt> 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 <tt>peer</tt> array. The bit-index
|
||||||
|
in the <tt>requested_blocks</tt> and <tt>finished_blocks</tt> correspons to the array-index into
|
||||||
|
<tt>peers</tt> and <tt>num_downloads</tt>. 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
|
||||||
|
<tt>requested_blocks</tt> is not set) the peer array entry will be undefined.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <tt>finished_blocks</tt> is a bitset where each bit says if the block is fully downloaded
|
||||||
|
or not. And the <tt>num_downloads</tt> 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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>get_peer_info()</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>get_peer_info()</tt> takes a reference to a vector that will be cleared and filled
|
<tt>get_peer_info()</tt> 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
|
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 <tt>src/sha1.c</tt>.
|
For more info, see <tt>src/sha1.c</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h1>Feedback</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There's a <a href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can usually find me as hydri in <tt>#btports @ irc.freenode.net</tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h1>Credits</h1>
|
<h1>Credits</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -35,12 +35,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/http_settings.hpp"
|
#include "libtorrent/http_settings.hpp"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
|
||||||
bool sleep_and_input(char* c)
|
bool sleep_and_input(char* c)
|
||||||
|
@ -54,6 +57,21 @@ bool sleep_and_input(char* c)
|
||||||
return false;
|
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
|
#else
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -155,6 +173,7 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<peer_info> peers;
|
std::vector<peer_info> peers;
|
||||||
|
std::vector<partial_piece_info> queue;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -164,6 +183,8 @@ int main(int argc, char* argv[])
|
||||||
if (c == 'q') break;
|
if (c == 'q') break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear();
|
||||||
|
set_cursor(0, 0);
|
||||||
for (std::vector<torrent_handle>::iterator i = handles.begin();
|
for (std::vector<torrent_handle>::iterator i = handles.begin();
|
||||||
i != handles.end();
|
i != handles.end();
|
||||||
++i)
|
++i)
|
||||||
|
@ -173,21 +194,19 @@ int main(int argc, char* argv[])
|
||||||
switch(s.state)
|
switch(s.state)
|
||||||
{
|
{
|
||||||
case torrent_status::queued_for_checking:
|
case torrent_status::queued_for_checking:
|
||||||
std::cout << "queued for checking: ";
|
std::cout << "queued ";
|
||||||
break;
|
break;
|
||||||
case torrent_status::checking_files:
|
case torrent_status::checking_files:
|
||||||
std::cout << "checking files: ";
|
std::cout << "checking ";
|
||||||
break;
|
break;
|
||||||
case torrent_status::downloading:
|
case torrent_status::downloading:
|
||||||
std::cout << "downloading: ";
|
std::cout << "dloading ";
|
||||||
break;
|
break;
|
||||||
case torrent_status::seeding:
|
case torrent_status::seeding:
|
||||||
std::cout << "seeding: ";
|
std::cout << "seeding ";
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::cout << s.progress*100 << "% ";
|
|
||||||
|
|
||||||
// calculate download and upload speeds
|
// calculate download and upload speeds
|
||||||
i->get_peer_info(peers);
|
i->get_peer_info(peers);
|
||||||
float down = 0.f;
|
float down = 0.f;
|
||||||
|
@ -205,14 +224,35 @@ int main(int argc, char* argv[])
|
||||||
total_down += i->total_download;
|
total_down += i->total_download;
|
||||||
total_up += i->total_upload;
|
total_up += i->total_upload;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
std::cout << "p:" << num_peers;
|
std::cout << boost::format("%f%% p:%d d:(%s) %s/s u:(%s) %s/s\n")
|
||||||
|
% (s.progress*100)
|
||||||
std::cout << " d:("
|
% num_peers
|
||||||
<< add_suffix(total_down) << ") " << add_suffix(down) << "/s up:("
|
% 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";
|
<< add_suffix(total_up) << ") " << add_suffix(up) << "/s\n";
|
||||||
|
|
||||||
|
i->get_download_queue(queue);
|
||||||
|
for (std::vector<partial_piece_info>::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)
|
catch (std::exception& e)
|
||||||
|
|
|
@ -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
|
|
|
@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef TORRENT_PEER_ID_HPP_INCLUDED
|
#ifndef TORRENT_PEER_ID_HPP_INCLUDED
|
||||||
#define TORRENT_PEER_ID_HPP_INCLUDED
|
#define TORRENT_PEER_ID_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -63,11 +65,14 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* begin() const { return m_number; }
|
typedef const unsigned char* const_iterator;
|
||||||
const unsigned char* end() const { return m_number+number_size; }
|
typedef unsigned char* iterator;
|
||||||
|
|
||||||
unsigned char* begin() { return m_number; }
|
const_iterator begin() const { return m_number; }
|
||||||
unsigned char* end() { return m_number+number_size; }
|
const_iterator end() const { return m_number+number_size; }
|
||||||
|
|
||||||
|
iterator begin() { return m_number; }
|
||||||
|
iterator end() { return m_number+number_size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -78,6 +83,19 @@ namespace libtorrent
|
||||||
typedef big_number peer_id;
|
typedef big_number peer_id;
|
||||||
typedef big_number sha1_hash;
|
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<unsigned int>(*i);
|
||||||
|
}
|
||||||
|
os << std::dec << std::cout << std::setfill(' ');
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_PEER_ID_HPP_INCLUDED
|
#endif // TORRENT_PEER_ID_HPP_INCLUDED
|
||||||
|
|
|
@ -37,6 +37,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "libtorrent/peer_id.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -60,6 +62,37 @@ namespace libtorrent
|
||||||
|
|
||||||
enum { max_blocks_per_piece = 128 };
|
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<max_blocks_per_piece> requested_blocks;
|
||||||
|
// the bit is set to one if the block has been acquired
|
||||||
|
std::bitset<max_blocks_per_piece> 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,
|
piece_picker(int blocks_per_piece,
|
||||||
int total_num_blocks);
|
int total_num_blocks);
|
||||||
|
|
||||||
|
@ -92,7 +125,8 @@ namespace libtorrent
|
||||||
// itself, by using the mark_as_downloading() member function.
|
// itself, by using the mark_as_downloading() member function.
|
||||||
// THIS IS DONE BY THE peer_connection::request_piece() MEMBER FUNCTION!
|
// THIS IS DONE BY THE peer_connection::request_piece() MEMBER FUNCTION!
|
||||||
void pick_pieces(const std::vector<bool>& pieces,
|
void pick_pieces(const std::vector<bool>& pieces,
|
||||||
std::vector<piece_block>& interesting_blocks) const;
|
std::vector<piece_block>& interesting_blocks,
|
||||||
|
int num_pieces) const;
|
||||||
|
|
||||||
// returns true if any client is currently downloading this
|
// returns true if any client is currently downloading this
|
||||||
// piece-block, or if it's queued for downloading by some client
|
// 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;
|
bool is_downloading(piece_block block) const;
|
||||||
|
|
||||||
// marks this piece-block as queued for downloading
|
// 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);
|
void mark_as_finished(piece_block block);
|
||||||
|
|
||||||
// if a piece had a hash-failure, it must be restured and
|
// 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);
|
void restore_piece(int index);
|
||||||
|
|
||||||
// clears the given piece's download flag
|
// clears the given piece's download flag
|
||||||
|
@ -113,9 +147,17 @@ namespace libtorrent
|
||||||
|
|
||||||
bool is_piece_finished(int index) const;
|
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;
|
int blocks_in_piece(int index) const;
|
||||||
|
|
||||||
|
// the number of downloaded blocks that hasn't passed
|
||||||
|
// the hash-check yet
|
||||||
int unverified_blocks() const;
|
int unverified_blocks() const;
|
||||||
|
|
||||||
|
void get_downloaders(std::vector<peer_id>& d, int index);
|
||||||
|
const std::vector<downloading_piece>& get_download_queue() const
|
||||||
|
{ return m_downloads; }
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// used in debug mode
|
// used in debug mode
|
||||||
void integrity_check(const torrent* t = 0) const;
|
void integrity_check(const torrent* t = 0) const;
|
||||||
|
@ -147,20 +189,7 @@ namespace libtorrent
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct downloading_piece
|
|
||||||
{
|
|
||||||
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
|
struct has_index
|
||||||
{
|
{
|
||||||
|
@ -173,9 +202,10 @@ namespace libtorrent
|
||||||
void move(bool downloading, int vec_index, int elem_index);
|
void move(bool downloading, int vec_index, int elem_index);
|
||||||
void remove(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<int>& piece_list,
|
int add_interesting_blocks(const std::vector<int>& piece_list,
|
||||||
const std::vector<bool>& pieces,
|
const std::vector<bool>& pieces,
|
||||||
std::vector<piece_block>& interesting_pieces) const;
|
std::vector<piece_block>& interesting_pieces,
|
||||||
|
int num_blocks) const;
|
||||||
|
|
||||||
// this vector contains all pieces we don't have.
|
// this vector contains all pieces we don't have.
|
||||||
// in the first entry (index 0) is a vector of all pieces
|
// in the first entry (index 0) is a vector of all pieces
|
||||||
|
|
|
@ -238,12 +238,21 @@ namespace libtorrent
|
||||||
void monitor_readability(boost::shared_ptr<socket> s) { m_readable.push_back(s); }
|
void monitor_readability(boost::shared_ptr<socket> s) { m_readable.push_back(s); }
|
||||||
void monitor_writability(boost::shared_ptr<socket> s) { m_writable.push_back(s); }
|
void monitor_writability(boost::shared_ptr<socket> s) { m_writable.push_back(s); }
|
||||||
void monitor_errors(boost::shared_ptr<socket> s) { m_error.push_back(s); }
|
void monitor_errors(boost::shared_ptr<socket> s) { m_error.push_back(s); }
|
||||||
|
/*
|
||||||
void clear_readable() { m_readable.clear(); }
|
void clear_readable() { m_readable.clear(); }
|
||||||
void clear_writable() { m_writable.clear(); }
|
void clear_writable() { m_writable.clear(); }
|
||||||
|
*/
|
||||||
void remove(boost::shared_ptr<socket> s);
|
void remove(boost::shared_ptr<socket> s);
|
||||||
|
|
||||||
|
void remove_writable(boost::shared_ptr<socket> s)
|
||||||
|
{ m_writable.erase(std::find(m_writable.begin(), m_writable.end(), s)); }
|
||||||
|
|
||||||
|
bool is_writability_monitored(boost::shared_ptr<socket> s)
|
||||||
|
{
|
||||||
|
return std::find(m_writable.begin(), m_writable.end(), s)
|
||||||
|
!= m_writable.end();
|
||||||
|
}
|
||||||
|
|
||||||
void wait(int timeout
|
void wait(int timeout
|
||||||
, std::vector<boost::shared_ptr<socket> >& readable
|
, std::vector<boost::shared_ptr<socket> >& readable
|
||||||
, std::vector<boost::shared_ptr<socket> >& writable
|
, std::vector<boost::shared_ptr<socket> >& writable
|
||||||
|
|
|
@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/peer_info.hpp"
|
#include "libtorrent/peer_info.hpp"
|
||||||
|
#include "libtorrent/piece_picker.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
|
@ -47,6 +48,11 @@ namespace libtorrent
|
||||||
struct checker_impl;
|
struct checker_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct duplicate_torrent: std::exception
|
||||||
|
{
|
||||||
|
virtual const char* what() const { return "torrent already exists in session"; }
|
||||||
|
};
|
||||||
|
|
||||||
struct torrent_status
|
struct torrent_status
|
||||||
{
|
{
|
||||||
enum state_t
|
enum state_t
|
||||||
|
@ -54,7 +60,6 @@ namespace libtorrent
|
||||||
invalid_handle,
|
invalid_handle,
|
||||||
queued_for_checking,
|
queued_for_checking,
|
||||||
checking_files,
|
checking_files,
|
||||||
connecting_to_tracker,
|
|
||||||
downloading,
|
downloading,
|
||||||
seeding
|
seeding
|
||||||
};
|
};
|
||||||
|
@ -65,6 +70,17 @@ namespace libtorrent
|
||||||
std::size_t total_upload;
|
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<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];
|
||||||
|
};
|
||||||
|
|
||||||
struct torrent_handle
|
struct torrent_handle
|
||||||
{
|
{
|
||||||
friend class session;
|
friend class session;
|
||||||
|
@ -76,6 +92,8 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent_status status() const;
|
torrent_status status() const;
|
||||||
|
|
||||||
|
void get_download_queue(std::vector<partial_piece_info>& queue) const;
|
||||||
|
|
||||||
// TODO: add a 'time to next announce' query.
|
// TODO: add a 'time to next announce' query.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -399,12 +399,21 @@ bool libtorrent::peer_connection::dispatch_message()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "hash-test failed. Some of these peers sent invalid data:\n";
|
||||||
|
std::vector<peer_id> downloaders;
|
||||||
|
picker.get_downloaders(downloaders, index);
|
||||||
|
std::copy(downloaders.begin(), downloaders.end(), std::ostream_iterator<peer_id>(std::cout, "\n"));
|
||||||
|
#endif
|
||||||
// we have to let the piece_picker know that
|
// we have to let the piece_picker know that
|
||||||
// this piece failed the check as it can restore it
|
// this piece failed the check as it can restore it
|
||||||
// and mark it as being interesting for download
|
// and mark it as being interesting for download
|
||||||
// TODO: do this more intelligently! and keep track
|
// TODO: do this more intelligently! and keep track
|
||||||
// of how much crap (data that failed hash-check) and
|
// of how much crap (data that failed hash-check) and
|
||||||
// how much redundant data we have downloaded
|
// 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);
|
picker.restore_piece(index);
|
||||||
}
|
}
|
||||||
m_torrent->get_policy().piece_finished(*this, index, verified);
|
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(block.piece_index < m_torrent->torrent_file().num_pieces());
|
||||||
assert(!m_torrent->picker().is_downloading(block));
|
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);
|
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
|
// throws exception when the client should be disconnected
|
||||||
void libtorrent::peer_connection::send_data()
|
void libtorrent::peer_connection::send_data()
|
||||||
{
|
{
|
||||||
|
assert(has_data());
|
||||||
|
|
||||||
// only add new piece-chunks if the send buffer is empty
|
// only add new piece-chunks if the send buffer is empty
|
||||||
// otherwise there will be no end to how large it will be!
|
// 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)
|
if (!m_requests.empty() && m_send_buffer.empty() && m_peer_interested && !m_choked)
|
||||||
|
|
|
@ -360,10 +360,16 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces, std::vector<piece_block>& interesting_pieces) const
|
void piece_picker::pick_pieces(const std::vector<bool>& pieces,
|
||||||
|
std::vector<piece_block>& interesting_pieces,
|
||||||
|
int num_blocks) const
|
||||||
{
|
{
|
||||||
assert(pieces.size() == m_piece_map.size());
|
assert(pieces.size() == m_piece_map.size());
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
integrity_check();
|
||||||
|
#endif
|
||||||
|
|
||||||
// free refers to pieces that are free to download, noone else
|
// free refers to pieces that are free to download, noone else
|
||||||
// is downloading them.
|
// is downloading them.
|
||||||
// partial is pieces that are partially being downloaded, and
|
// partial is pieces that are partially being downloaded, and
|
||||||
|
@ -378,10 +384,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
if (add_interesting_blocks(*partial, pieces, interesting_pieces))
|
num_blocks = add_interesting_blocks(*partial, pieces, interesting_pieces, num_blocks);
|
||||||
{
|
if (num_blocks == 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
++partial;
|
++partial;
|
||||||
if (partial == m_downloading_piece_info.end()) break;
|
if (partial == m_downloading_piece_info.end()) break;
|
||||||
}
|
}
|
||||||
|
@ -389,18 +393,17 @@ namespace libtorrent
|
||||||
|
|
||||||
if (free != m_piece_info.end())
|
if (free != m_piece_info.end())
|
||||||
{
|
{
|
||||||
if (add_interesting_blocks(*free, pieces, interesting_pieces))
|
num_blocks = add_interesting_blocks(*free, pieces, interesting_pieces, num_blocks);
|
||||||
{
|
if (num_blocks == 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
++free;
|
++free;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool piece_picker::add_interesting_blocks(const std::vector<int>& piece_list,
|
int piece_picker::add_interesting_blocks(const std::vector<int>& piece_list,
|
||||||
const std::vector<bool>& pieces,
|
const std::vector<bool>& pieces,
|
||||||
std::vector<piece_block>& interesting_blocks) const
|
std::vector<piece_block>& interesting_blocks,
|
||||||
|
int num_blocks) const
|
||||||
{
|
{
|
||||||
|
|
||||||
for (std::vector<int>::const_iterator i = piece_list.begin();
|
for (std::vector<int>::const_iterator i = piece_list.begin();
|
||||||
|
@ -417,16 +420,21 @@ namespace libtorrent
|
||||||
// we can break our search (return)
|
// we can break our search (return)
|
||||||
|
|
||||||
if (m_piece_map[*i].downloading == 0)
|
if (m_piece_map[*i].downloading == 0)
|
||||||
|
{
|
||||||
|
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));
|
interesting_blocks.push_back(piece_block(*i, 0));
|
||||||
return true; // we have found a piece that's free to download
|
}
|
||||||
|
num_blocks -= piece_blocks;
|
||||||
|
if (num_blocks == 0) return num_blocks;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the number of blocks in this
|
// calculate the number of blocks in this
|
||||||
// piece. It's always m_blocks_per_piece, except
|
// piece. It's always m_blocks_per_piece, except
|
||||||
// in the last piece.
|
// in the last piece.
|
||||||
int num_blocks_in_piece
|
int num_blocks_in_piece = blocks_in_piece(*i);
|
||||||
= (*i == m_piece_map.size()-1)?m_blocks_in_last_piece:m_blocks_per_piece;
|
|
||||||
|
|
||||||
std::vector<downloading_piece>::const_iterator p
|
std::vector<downloading_piece>::const_iterator p
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
= 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));
|
interesting_blocks.push_back(piece_block(*i, j));
|
||||||
if (p->requested_blocks[j] == 0)
|
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
|
bool piece_picker::is_piece_finished(int index) const
|
||||||
|
@ -471,7 +483,7 @@ namespace libtorrent
|
||||||
return i->requested_blocks[block.block_index];
|
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
|
#ifndef NDEBUG
|
||||||
integrity_check();
|
integrity_check();
|
||||||
|
@ -488,6 +500,7 @@ namespace libtorrent
|
||||||
downloading_piece dp;
|
downloading_piece dp;
|
||||||
dp.index = block.piece_index;
|
dp.index = block.piece_index;
|
||||||
dp.requested_blocks[block.block_index] = 1;
|
dp.requested_blocks[block.block_index] = 1;
|
||||||
|
dp.info[block.block_index].peer = peer;
|
||||||
m_downloads.push_back(dp);
|
m_downloads.push_back(dp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -496,6 +509,7 @@ namespace libtorrent
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
assert(i->requested_blocks[block.block_index] == 0);
|
assert(i->requested_blocks[block.block_index] == 0);
|
||||||
|
i->info[block.block_index].peer = peer;
|
||||||
i->requested_blocks[block.block_index] = 1;
|
i->requested_blocks[block.block_index] = 1;
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -518,11 +532,24 @@ namespace libtorrent
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
assert(i->requested_blocks[block.block_index] == 1);
|
assert(i->requested_blocks[block.block_index] == 1);
|
||||||
i->finished_blocks[block.block_index] = 1;
|
i->finished_blocks[block.block_index] = 1;
|
||||||
|
i->info[block.block_index].num_downloads++;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
integrity_check();
|
integrity_check();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_picker::get_downloaders(std::vector<peer_id>& d, int index)
|
||||||
|
{
|
||||||
|
std::vector<downloading_piece>::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)
|
void piece_picker::abort_download(piece_block block)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,13 +39,30 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// we try to maintain 4 requested blocks in the download
|
||||||
|
// queue
|
||||||
|
request_queue = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
void request_a_block(torrent& t, peer_connection& c)
|
void request_a_block(torrent& t, peer_connection& c)
|
||||||
{
|
{
|
||||||
piece_picker& p = t.picker();
|
piece_picker& p = t.picker();
|
||||||
std::vector<piece_block> interesting_pieces;
|
std::vector<piece_block> interesting_pieces;
|
||||||
interesting_pieces.reserve(100);
|
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
|
// this vector is filled with the interestin pieces
|
||||||
// that some other peer is currently downloading
|
// that some other peer is currently downloading
|
||||||
|
@ -68,7 +85,8 @@ namespace
|
||||||
// ok, we found a piece that's not being downloaded
|
// ok, we found a piece that's not being downloaded
|
||||||
// by somebody else. request it from this peer
|
// by somebody else. request it from this peer
|
||||||
c.request_block(*i);
|
c.request_block(*i);
|
||||||
return;
|
num_requests++;
|
||||||
|
if (num_requests >= request_queue) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: compare this peer's bandwidth against the
|
// TODO: compare this peer's bandwidth against the
|
||||||
|
|
|
@ -182,6 +182,8 @@ namespace libtorrent
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_logger = create_log("main session");
|
m_logger = create_log("main session");
|
||||||
#endif
|
#endif
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
boost::shared_ptr<socket> listener(new socket(socket::tcp, false));
|
boost::shared_ptr<socket> listener(new socket(socket::tcp, false));
|
||||||
int max_port = m_listen_port + 9;
|
int max_port = m_listen_port + 9;
|
||||||
|
@ -233,6 +235,11 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::clock_t time__ = std::clock();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// if nothing happens within 500000 microseconds (0.5 seconds)
|
// if nothing happens within 500000 microseconds (0.5 seconds)
|
||||||
// do the loop anyway to check if anything else has changed
|
// do the loop anyway to check if anything else has changed
|
||||||
// (*m_logger) << "sleeping\n";
|
// (*m_logger) << "sleeping\n";
|
||||||
|
@ -243,6 +250,10 @@ namespace libtorrent
|
||||||
num_loops++;
|
num_loops++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
assert(readable_clients.size() + writable_clients.size() + error_clients.size() > 0
|
||||||
|
|| (std::clock() - time__) > CLOCKS_PER_SEC / 3);
|
||||||
|
|
||||||
// +1 for the listen socket
|
// +1 for the listen socket
|
||||||
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
|
assert(m_selector.count_read_monitors() == m_connections.size() + 1);
|
||||||
|
|
||||||
|
@ -262,6 +273,7 @@ namespace libtorrent
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************
|
// ************************
|
||||||
// RECEIVE SOCKETS
|
// RECEIVE SOCKETS
|
||||||
// ************************
|
// ************************
|
||||||
|
@ -297,7 +309,6 @@ namespace libtorrent
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
connection_map::iterator p = m_connections.find(*i);
|
connection_map::iterator p = m_connections.find(*i);
|
||||||
if(p == m_connections.end())
|
if(p == m_connections.end())
|
||||||
{
|
{
|
||||||
|
@ -321,7 +332,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ************************
|
// ************************
|
||||||
// SEND SOCKETS
|
// SEND SOCKETS
|
||||||
// ************************
|
// ************************
|
||||||
|
@ -342,8 +352,15 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
assert(m_selector.is_writability_monitored(p->first));
|
||||||
|
assert(p->second->has_data());
|
||||||
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
|
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
|
||||||
p->second->send_data();
|
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&)
|
catch(network_error&)
|
||||||
{
|
{
|
||||||
|
@ -374,16 +391,27 @@ namespace libtorrent
|
||||||
if (p != m_connections.end()) m_connections.erase(p);
|
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
|
// clear all writablility monitors and add
|
||||||
// the ones who still has data to send
|
// the ones who still has data to send
|
||||||
m_selector.clear_writable();
|
/* m_selector.clear_writable();
|
||||||
|
|
||||||
|
|
||||||
// ************************
|
// ************************
|
||||||
// BUILD WRITER LIST
|
// 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
|
// loop over all clients and purge the ones that has timed out
|
||||||
// and check if they have pending data to be sent
|
// and check if they have pending data to be sent
|
||||||
|
@ -411,7 +439,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// (*m_logger) << "time: " << std::clock()-timer << "\n";
|
// (*m_logger) << "time: " << std::clock()-timer << "\n";
|
||||||
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
|
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
|
||||||
if (d.seconds() < 1) continue;
|
if (d.seconds() < 1) continue;
|
||||||
|
@ -422,18 +450,41 @@ namespace libtorrent
|
||||||
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
|
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
|
||||||
// ************************
|
// ************************
|
||||||
|
|
||||||
|
|
||||||
#ifdef TORRENT_DEBUG_SOCKETS
|
#ifdef TORRENT_DEBUG_SOCKETS
|
||||||
std::cout << "\nloops: " << num_loops << "\n";
|
std::cout << "\nloops: " << num_loops << "\n";
|
||||||
assert(loops < 1300);
|
if (num_loops > 1300)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
}
|
||||||
num_loops = 0;
|
num_loops = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// do the second_tick() on each connection
|
// do the second_tick() on each connection
|
||||||
// this will update their statistics (download and upload speeds)
|
// 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();
|
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
|
// check each torrent for abortion or
|
||||||
|
@ -484,6 +535,17 @@ namespace libtorrent
|
||||||
t.nsec += 1000000;
|
t.nsec += 1000000;
|
||||||
boost::thread::sleep(t);
|
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
|
// 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,
|
torrent_handle session::add_torrent(const torrent_info& ti,
|
||||||
const std::string& save_path)
|
const std::string& save_path)
|
||||||
{
|
{
|
||||||
|
@ -507,9 +570,8 @@ namespace libtorrent
|
||||||
boost::mutex::scoped_lock l(m_impl.m_mutex);
|
boost::mutex::scoped_lock l(m_impl.m_mutex);
|
||||||
|
|
||||||
// is the torrent already active?
|
// is the torrent already active?
|
||||||
// TODO: this should throw
|
|
||||||
if (m_impl.find_torrent(ti.info_hash()))
|
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);
|
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
|
||||||
|
|
||||||
// is the torrent currently being checked?
|
// is the torrent currently being checked?
|
||||||
// TODO: This should throw
|
|
||||||
if (m_checker_impl.find_torrent(ti.info_hash()))
|
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
|
// create the torrent and the data associated with
|
||||||
|
|
|
@ -187,9 +187,9 @@ namespace libtorrent
|
||||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||||
<< static_cast<unsigned int>(*j);
|
<< static_cast<unsigned int>(*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
|
// for each of the peers we got from the tracker
|
||||||
|
|
|
@ -143,11 +143,44 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& 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<piece_picker::downloading_piece>& q
|
||||||
|
= p.get_download_queue();
|
||||||
|
|
||||||
|
for (std::vector<piece_picker::downloading_piece>::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()
|
void torrent_handle::abort()
|
||||||
{
|
{
|
||||||
if (m_ses == 0) return;
|
if (m_ses == 0) return;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
torrent* t = m_ses->find_torrent(m_info_hash);
|
||||||
|
|
Loading…
Reference in New Issue