diff --git a/docs/manual.html b/docs/manual.html index 496722963..5b128ea26 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -357,14 +357,16 @@ the session, it conta entry const& e , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); void remove_torrent(torrent_handle const& h); @@ -430,13 +432,16 @@ torrent_handle add_torrent( entry const& e , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); + torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024);

You add torrents through the add_torrent() function where you give an @@ -455,6 +460,10 @@ are rearranged to finally be in their correct places once the entire torrent has downloaded. If it is false, the entire storage is allocated before download begins. I.e. the files contained in the torrent are filled with zeroes, and each downloaded piece is put in its final place directly when downloaded.

+

block_size sets the preferred request size, i.e. the number of bytes to request from +a peer at a time. This block size must be a divisor of the piece size, and since the piece +size is an even power of 2, so must the block size be. If the block size given here turns +out to be greater than the piece size, it will simply be clamped to the piece size.

The torrent_handle returned by add_torrent() can be used to retrieve information about the torrent's progress, its peers etc. It is also used to abort a torrent.

The second overload that takes a tracker url and an info-hash instead of metadata (entry) diff --git a/docs/manual.rst b/docs/manual.rst index df88fe425..5ef67e478 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -226,14 +226,16 @@ The ``session`` class has the following synopsis:: entry const& e , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); void remove_torrent(torrent_handle const& h); @@ -303,13 +305,16 @@ add_torrent() entry const& e , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); + torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); You add torrents through the ``add_torrent()`` function where you give an object representing the information found in the torrent file and the path where you @@ -331,6 +336,11 @@ downloaded. If it is false, the entire storage is allocated before download begi the files contained in the torrent are filled with zeroes, and each downloaded piece is put in its final place directly when downloaded. +``block_size`` sets the preferred request size, i.e. the number of bytes to request from +a peer at a time. This block size must be a divisor of the piece size, and since the piece +size is an even power of 2, so must the block size be. If the block size given here turns +out to be greater than the piece size, it will simply be clamped to the piece size. + The torrent_handle_ returned by ``add_torrent()`` can be used to retrieve information about the torrent's progress, its peers etc. It is also used to abort a torrent. diff --git a/examples/client_test.cpp b/examples/client_test.cpp index b975a69a1..36110be55 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -372,7 +372,7 @@ int main(int argc, char* argv[]) catch (invalid_encoding&) {} catch (boost::filesystem::filesystem_error&) {} - handles.push_back(ses.add_torrent(e, save_path, resume_data)); + handles.push_back(ses.add_torrent(e, save_path, resume_data, true, 128 * 1024)); handles.back().set_max_connections(100); handles.back().set_max_uploads(-1); handles.back().set_ratio(1.02f); diff --git a/include/libtorrent/ip_filter.hpp b/include/libtorrent/ip_filter.hpp index 44837b859..99e0d2989 100644 --- a/include/libtorrent/ip_filter.hpp +++ b/include/libtorrent/ip_filter.hpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include +#include namespace libtorrent { @@ -51,7 +52,7 @@ public: ip_filter(); void add_rule(address first, address last, int flags); int access(address const& addr) const; - //void print() const; + void print() const; private: struct range diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 39da5f978..5101fc729 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -317,14 +317,16 @@ namespace libtorrent entry const& metadata , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& resume_data = entry() - , bool compact_mode = true); + , bool compact_mode = true + , int block_size = 16 * 1024); session_status status() const; diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index d13479f64..e691b07e6 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -96,7 +96,8 @@ namespace libtorrent , entry const& metadata , boost::filesystem::path const& save_path , address const& net_interface - , bool compact_mode); + , bool compact_mode + , int block_size); // used with metadata-less torrents // (the metadata is downloaded from the peers) @@ -106,7 +107,8 @@ namespace libtorrent , sha1_hash const& info_hash , boost::filesystem::path const& save_path , address const& net_interface - , bool compact_mode); + , bool compact_mode + , int block_size); ~torrent(); @@ -525,6 +527,10 @@ namespace libtorrent int m_metadata_progress; int m_metadata_size; + + // defaults to 16 kiB, but can be set by the user + // when creating the torrent + const int m_default_block_size; }; inline boost::posix_time::ptime torrent::next_announce() const diff --git a/src/ip_filter.cpp b/src/ip_filter.cpp index ac50cf51a..65ab7baa4 100644 --- a/src/ip_filter.cpp +++ b/src/ip_filter.cpp @@ -59,12 +59,15 @@ namespace libtorrent assert(j != i); int first_access = i->access; -/* + std::cout << "flags: " << flags << "\n"; std::cout << "first_access: " << first_access << "\n"; std::cout << "i->start: " << i->start.as_string() << "\n"; std::cout << "first: " << first.as_string() << "\n"; -*/ + + int last_access = last_access = prior(j)->access; + std::cout << "last_access: " << last_access << "\n"; + if (i->start != first && first_access != flags) { i = m_access_list.insert(i, range(address(first.ip(), 0), flags)); @@ -74,22 +77,20 @@ namespace libtorrent --i; first_access = i->access; } -/* + std::cout << "distance(i, j): " << std::distance(i, j) << "\n"; std::cout << "size(): " << m_access_list.size() << "\n"; -*/ + assert(!m_access_list.empty()); assert(i != m_access_list.end()); - int last_access = last_access = prior(j)->access; -// std::cout << "last_access: " << last_access << "\n"; if (i != j) m_access_list.erase(next(i), j); -/* + std::cout << "size(): " << m_access_list.size() << "\n"; std::cout << "last: " << last.as_string() << "\n"; std::cout << "last.ip(): " << last.ip() << " " << 0xffffffff << "\n"; -*/ + if (i->start == first) { // we can do this const-cast because we know that the new @@ -106,6 +107,7 @@ namespace libtorrent || (j == m_access_list.end() && last.ip() != 0xffffffff)) { assert(j == m_access_list.end() || last.ip() < j->start.ip() - 1); + std::cout << " -- last_access: " << last_access << "\n"; if (last_access != flags) j = m_access_list.insert(j, range(address(last.ip() + 1, 0), last_access)); } @@ -124,7 +126,7 @@ namespace libtorrent || addr < boost::next(i)->start)); return i->access; } -/* + void ip_filter::print() const { for (range_t::iterator i = m_access_list.begin(); i != m_access_list.end(); ++i) @@ -132,6 +134,6 @@ namespace libtorrent std::cout << i->start.as_string() << " " << i->access << "\n"; } } -*/ + } diff --git a/src/session.cpp b/src/session.cpp index 48414789e..e8d2b4a2f 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -963,8 +963,22 @@ namespace libtorrent entry const& metadata , boost::filesystem::path const& save_path , entry const& resume_data - , bool compact_mode) + , bool compact_mode + , int block_size) { + // make sure the block_size is an even power of 2 +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (block_size & (1 << i)) + { + assert((block_size & ~(1 << i)) == 0); + break; + } + } +#endif + + assert(!save_path.empty()); torrent_info ti(metadata); @@ -992,7 +1006,7 @@ namespace libtorrent // the thread boost::shared_ptr torrent_ptr( new torrent(m_impl, metadata, save_path, m_impl.m_listen_interface - , compact_mode)); + , compact_mode, block_size)); detail::piece_checker_data d; d.torrent_ptr = torrent_ptr; @@ -1014,8 +1028,21 @@ namespace libtorrent , sha1_hash const& info_hash , boost::filesystem::path const& save_path , entry const& - , bool compact_mode) + , bool compact_mode + , int block_size) { + // make sure the block_size is an even power of 2 +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (block_size & (1 << i)) + { + assert((block_size & ~(1 << i)) == 0); + break; + } + } +#endif + // TODO: support resume data in this case assert(!save_path.empty()); { @@ -1043,7 +1070,7 @@ namespace libtorrent // the thread boost::shared_ptr torrent_ptr( new torrent(m_impl, tracker_url, info_hash, save_path - , m_impl.m_listen_interface, compact_mode)); + , m_impl.m_listen_interface, compact_mode, block_size)); m_impl.m_torrents.insert( std::make_pair(info_hash, torrent_ptr)).first; @@ -1289,85 +1316,83 @@ namespace libtorrent tmp_pieces.push_back(index); } - - int num_blocks_per_piece = (int)rd["blocks per piece"].integer(); - if (num_blocks_per_piece != info.piece_length() / torrent_ptr->block_size()) - { - error = "invalid number of blocks per piece (" - + boost::lexical_cast(num_blocks_per_piece) + ")"; - return; - } - - // the unfinished pieces - - entry::list_type& unfinished = rd["unfinished"].list(); - + // only bother to check the partial pieces if we have the same block size + // as in the fast resume data. If the blocksize has changed, then throw + // away all partial pieces. std::vector tmp_unfinished; - tmp_unfinished.reserve(unfinished.size()); - for (entry::list_type::iterator i = unfinished.begin(); - i != unfinished.end(); ++i) + int num_blocks_per_piece = (int)rd["blocks per piece"].integer(); + if (num_blocks_per_piece == info.piece_length() / torrent_ptr->block_size()) { - piece_picker::downloading_piece p; + // the unfinished pieces - p.index = (int)(*i)["piece"].integer(); - if (p.index < 0 || p.index >= info.num_pieces()) - { - error = "invalid piece index in unfinished piece list (index: " - + boost::lexical_cast(p.index) + " size: " - + boost::lexical_cast(info.num_pieces()) + ")"; - return; - } + entry::list_type& unfinished = rd["unfinished"].list(); - const std::string& bitmask = (*i)["bitmask"].string(); - - const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); - if ((int)bitmask.size() != num_bitmask_bytes) + tmp_unfinished.reserve(unfinished.size()); + for (entry::list_type::iterator i = unfinished.begin(); + i != unfinished.end(); ++i) { - error = "invalid size of bitmask (" + boost::lexical_cast(bitmask.size()) + ")"; - return; - } - for (int j = 0; j < num_bitmask_bytes; ++j) - { - unsigned char bits = bitmask[j]; - for (int k = 0; k < 8; ++k) + piece_picker::downloading_piece p; + + p.index = (int)(*i)["piece"].integer(); + if (p.index < 0 || p.index >= info.num_pieces()) { - const int bit = j * 8 + k; - if (bits & (1 << k)) - p.finished_blocks[bit] = true; + error = "invalid piece index in unfinished piece list (index: " + + boost::lexical_cast(p.index) + " size: " + + boost::lexical_cast(info.num_pieces()) + ")"; + return; } + + const std::string& bitmask = (*i)["bitmask"].string(); + + const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); + if ((int)bitmask.size() != num_bitmask_bytes) + { + error = "invalid size of bitmask (" + boost::lexical_cast(bitmask.size()) + ")"; + return; + } + for (int j = 0; j < num_bitmask_bytes; ++j) + { + unsigned char bits = bitmask[j]; + for (int k = 0; k < 8; ++k) + { + const int bit = j * 8 + k; + if (bits & (1 << k)) + p.finished_blocks[bit] = true; + } + } + + if (p.finished_blocks.count() == 0) continue; + + std::vector::iterator slot_iter + = std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index); + if (slot_iter == tmp_pieces.end()) + { + // this piece is marked as unfinished + // but doesn't have any storage + error = "piece " + boost::lexical_cast(p.index) + " is " + "marked as unfinished, but doesn't have any storage"; + return; + } + + assert(*slot_iter == p.index); + int slot_index = static_cast(slot_iter - tmp_pieces.begin()); + unsigned long adler + = torrent_ptr->filesystem().piece_crc( + slot_index + , torrent_ptr->block_size() + , p.finished_blocks); + + const entry& ad = (*i)["adler32"]; + + // crc's didn't match, don't use the resume data + if (ad.integer() != adler) + { + error = "checksum mismatch on piece " + boost::lexical_cast(p.index); + return; + } + + tmp_unfinished.push_back(p); } - - if (p.finished_blocks.count() == 0) continue; - - std::vector::iterator slot_iter - = std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index); - if (slot_iter == tmp_pieces.end()) - { - // this piece is marked as unfinished - // but doesn't have any storage - error = "piece " + boost::lexical_cast(p.index) + " is " - "marked as unfinished, but doesn't have any storage"; - return; - } - - assert(*slot_iter == p.index); - int slot_index = static_cast(slot_iter - tmp_pieces.begin()); - unsigned long adler - = torrent_ptr->filesystem().piece_crc( - slot_index - , torrent_ptr->block_size() - , p.finished_blocks); - - const entry& ad = (*i)["adler32"]; - - // crc's didn't match, don't use the resume data - if (ad.integer() != adler) - { - error = "checksum mismatch on piece " + boost::lexical_cast(p.index); - return; - } - - tmp_unfinished.push_back(p); } // verify file sizes diff --git a/src/torrent.cpp b/src/torrent.cpp index bb69653b6..1ee7ae636 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -88,9 +88,9 @@ namespace , tracker_failed_max = 5 }; - int calculate_block_size(const torrent_info& i) + int calculate_block_size(const torrent_info& i, int default_block_size) { - const int default_block_size = 16 * 1024; + if (default_block_size < 1024) default_block_size = 1024; // if pieces are too small, adjust the block size if (i.piece_length() < default_block_size) @@ -151,7 +151,8 @@ namespace libtorrent , entry const& metadata , boost::filesystem::path const& save_path , address const& net_interface - , bool compact_mode) + , bool compact_mode + , int block_size) : m_torrent_file(metadata) , m_abort(false) , m_paused(false) @@ -183,6 +184,7 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_metadata_progress(0) , m_metadata_size(0) + , m_default_block_size(block_size) { m_uploads_quota.min = 2; m_connections_quota.min = 2; @@ -203,7 +205,8 @@ namespace libtorrent , sha1_hash const& info_hash , boost::filesystem::path const& save_path , address const& net_interface - , bool compact_mode) + , bool compact_mode + , int block_size) : m_torrent_file(info_hash) , m_abort(false) , m_paused(false) @@ -234,6 +237,7 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_metadata_progress(0) , m_metadata_size(0) + , m_default_block_size(block_size) { m_uploads_quota.min = 2; m_connections_quota.min = 2; @@ -263,7 +267,7 @@ namespace libtorrent m_have_pieces.resize(m_torrent_file.num_pieces(), false); m_storage = std::auto_ptr(new piece_manager(m_torrent_file, m_save_path)); - m_block_size = calculate_block_size(m_torrent_file); + m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); m_picker = std::auto_ptr(new piece_picker( static_cast(m_torrent_file.piece_length() / m_block_size) , static_cast((m_torrent_file.total_size()+m_block_size-1)/m_block_size))); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 5b194b6d2..6bffe7675 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -149,7 +149,7 @@ namespace libtorrent void torrent_info::set_piece_size(int size) { - // make sure the size is an even 2 exponential + // make sure the size is an even power of 2 #ifndef NDEBUG for (int i = 0; i < 32; ++i) {