diff --git a/Jamfile b/Jamfile index c539c1d6c..c493aaf22 100755 --- a/Jamfile +++ b/Jamfile @@ -20,7 +20,7 @@ project torrent release:NDEBUG BOOST_ALL_NO_LIB _FILE_OFFSET_BITS=64 - /boost/thread//boost_thread/ + /boost/thread//boost_thread /boost/filesystem//boost_filesystem/static /boost/date_time//boost_date_time/static static diff --git a/docs/manual.rst b/docs/manual.rst index 90d2948ab..0e5b4b316 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -2193,7 +2193,7 @@ The file format is a bencoded dictionary containing the following fields: | | greater than 4 megabytes, the block size will increase. | | | | +----------------------+--------------------------------------------------------------+ -| ``slots`` | list of integers. The list mappes slots ti piece indices. It | +| ``slots`` | list of integers. The list mappes slots to piece indices. It | | | tells which piece is on which slot. If piece index is -2 it | | | means it is free, that there's no piece there. If it is -1, | | | means the slot isn't allocated on disk yet. The pieces have | diff --git a/examples/Jamfile b/examples/Jamfile index a01d2cdc0..7fa51623c 100755 --- a/examples/Jamfile +++ b/examples/Jamfile @@ -23,5 +23,5 @@ exe make_torrent ; -stage bin : dump_torrent make_torrent simple_client client_test ; +stage . : dump_torrent make_torrent simple_client client_test ; diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index d947d1ffa..3e8718136 100755 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -78,6 +78,7 @@ int main(int argc, char* argv[]) std::cout << "number of pieces: " << t.num_pieces() << "\n"; std::cout << "piece length: " << t.piece_length() << "\n"; + std::cout << "info hash: " << t.info_hash() << "\n"; std::cout << "files:\n"; for (torrent_info::file_iterator i = t.begin_files(); i != t.end_files(); diff --git a/examples/make_torrent.cpp b/examples/make_torrent.cpp index 41a383208..4973e7ca1 100755 --- a/examples/make_torrent.cpp +++ b/examples/make_torrent.cpp @@ -77,8 +77,7 @@ int main(int argc, char* argv[]) if (argc != 4) { - std::cerr << "usage: make_torrent \n\n" - "the torrent file will be written to stdout.\n"; + std::cerr << "usage: make_torrent \n"; return 1; } @@ -112,7 +111,7 @@ int main(int argc, char* argv[]) t.set_creator(creator_str); - // create the torrent and print it to stdout + // create the torrent and print it to out entry e = t.create_torrent(); libtorrent::bencode(std::ostream_iterator(out), e); } diff --git a/include/libtorrent/fingerprint.hpp b/include/libtorrent/fingerprint.hpp index 8d397d4f2..587601e71 100755 --- a/include/libtorrent/fingerprint.hpp +++ b/include/libtorrent/fingerprint.hpp @@ -57,10 +57,10 @@ namespace libtorrent , tag_version(tag) { assert(id_string); - assert(major >= 0 && major < 10); - assert(minor >= 0 && minor < 10); - assert(revision >= 0 && revision < 10); - assert(tag >= 0 && tag < 10); + assert(major >= 0); + assert(minor >= 0); + assert(revision >= 0); + assert(tag >= 0); assert(std::strlen(id_string) == 2); id[0] = id_string[0]; id[1] = id_string[1]; @@ -70,10 +70,10 @@ namespace libtorrent { std::stringstream s; s << "-" << id[0] << id[1] - << (int)major_version - << (int)minor_version - << (int)revision_version - << (int)tag_version << "-"; + << version_to_char(major_version) + << version_to_char(minor_version) + << version_to_char(revision_version) + << version_to_char(tag_version) << "-"; return s.str(); } @@ -83,6 +83,15 @@ namespace libtorrent char revision_version; char tag_version; + private: + + char version_to_char(int v) const + { + if (v >= 0 && v < 10) return '0' + v; + else if (v >= 10) return 'A' + (v - 10); + assert(false); + } + }; } diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index c5c371d8e..899a10959 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -145,8 +145,8 @@ namespace libtorrent mutable boost::mutex m_mutex; boost::condition m_cond; - // a list of all torrents that are currently checking - // their files (in separate threads) + // a list of all torrents that are currently in queue + // or checking their files std::deque m_torrents; bool m_abort; @@ -260,7 +260,6 @@ namespace libtorrent boost::shared_ptr m_logger; #endif }; - } struct http_settings; @@ -296,6 +295,8 @@ namespace libtorrent ~session(); + std::vector get_torrents(); + // all torrent_handles must be destructed before the session is destructed! torrent_handle add_torrent( entry const& metadata diff --git a/include/libtorrent/version.hpp b/include/libtorrent/version.hpp index 0b7c5adb4..5e9502a79 100755 --- a/include/libtorrent/version.hpp +++ b/include/libtorrent/version.hpp @@ -33,6 +33,6 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_VERSION_HPP_INCLUDED #define TORRENT_VERSION_HPP_INCLUDED -#define LIBTORRENT_VERSION "0.1.0.0" +#define LIBTORRENT_VERSION "0.9.0.0" #endif diff --git a/src/escape_string.cpp b/src/escape_string.cpp index a727d478d..ada4b01a9 100755 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -97,24 +97,21 @@ namespace libtorrent // section 2.3 // some trackers seems to require that ' is escaped // static const char unreserved_chars[] = "-_.!~*'()"; - static const char unreserved_chars[] = "-_.!~*()"; + static const char unreserved_chars[] = "-_.!~*()" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789"; std::stringstream ret; ret << std::hex << std::setfill('0'); for (int i = 0; i < len; ++i) { - if (std::isalnum(static_cast(*str)) - || std::count( + if (std::count( unreserved_chars , unreserved_chars+sizeof(unreserved_chars)-1 , *str)) { ret << *str; } - else if (*str == ' ') - { - ret << '+'; - } else { ret << '%' diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 9a445d440..196d9fd9b 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1710,7 +1710,8 @@ namespace libtorrent // if we have an infinite ratio, just say we have downloaded // much more than we have uploaded. And we'll keep uploading. - if (ratio == 0.f) return std::numeric_limits::max(); + if (ratio == 0.f) + return std::numeric_limits::max(); return m_free_upload + static_cast(m_statistics.total_payload_download() * ratio) diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 881bc2424..6dfec3244 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -133,7 +133,7 @@ namespace libtorrent } } #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } @@ -368,7 +368,7 @@ namespace libtorrent move(true, m_piece_map[index].peer_count, m_piece_map[index].index); #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } @@ -389,7 +389,7 @@ namespace libtorrent move(m_piece_map[i].downloading, peer_count, index); #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif return; } @@ -403,7 +403,8 @@ namespace libtorrent int index = m_piece_map[i].index; assert(m_piece_map[i].peer_count > 0); - m_piece_map[i].peer_count--; + if (m_piece_map[i].peer_count > 0) + m_piece_map[i].peer_count--; if (index == 0xffffff) return; move(m_piece_map[i].downloading, peer_count, index); @@ -422,7 +423,7 @@ namespace libtorrent assert(info_index != 0xffffff); remove(m_piece_map[index].downloading, peer_count, info_index); #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } @@ -434,7 +435,7 @@ namespace libtorrent assert(pieces.size() == m_piece_map.size()); #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif // free refers to pieces that are free to download, noone else @@ -581,7 +582,7 @@ namespace libtorrent void piece_picker::mark_as_downloading(piece_block block, const address& peer) { #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif assert(block.piece_index >= 0); assert(block.block_index >= 0); @@ -610,14 +611,14 @@ namespace libtorrent i->requested_blocks[block.block_index] = 1; } #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } void piece_picker::mark_as_finished(piece_block block, const address& peer) { #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif assert(block.piece_index >= 0); assert(block.block_index >= 0); @@ -647,7 +648,7 @@ namespace libtorrent i->finished_blocks[block.block_index] = 1; } #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } /* @@ -716,7 +717,7 @@ namespace libtorrent void piece_picker::abort_download(piece_block block) { #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif assert(block.piece_index >= 0); @@ -751,7 +752,7 @@ namespace libtorrent move(true, m_piece_map[block.piece_index].peer_count, m_piece_map[block.piece_index].index); } #ifndef NDEBUG -// integrity_check(); + integrity_check(); #endif } diff --git a/src/policy.cpp b/src/policy.cpp index d93e9defb..11f6ba64e 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -237,9 +237,10 @@ namespace { // if the peer is interested in us, it means it may // want to trade it's surplus uploads for downloads itself - // (and we should consider it free). If the share diff is + // (and we should not consider it free). If the share diff is // negative, there's no free download to get from this peer. size_type diff = i->second->share_diff(); + assert(diff < std::numeric_limits::max()); if (i->second->is_peer_interested() || diff <= 0) continue; @@ -265,7 +266,9 @@ namespace size_type total_diff = 0; for (torrent::peer_iterator i = start; i != end; ++i) { - total_diff += i->second->share_diff(); + size_type d = i->second->share_diff(); + assert(d < std::numeric_limits::max()); + total_diff += d; if (!i->second->is_peer_interested() || i->second->share_diff() >= 0) continue; ++num_peers; } @@ -481,14 +484,18 @@ namespace libtorrent // first choice candidate. // it is a candidate we owe nothing to and which has been unchoked // the longest. + using namespace boost::posix_time; + using namespace boost::gregorian; + peer* candidate = 0; - boost::posix_time::ptime last_unchoke // not valid when candidate==0 - = boost::posix_time::ptime(boost::posix_time::ptime(boost::gregorian::date(1970, boost::gregorian::Jan, 1))); + + // not valid when candidate == 0 + ptime last_unchoke = ptime(date(1970, Jan, 1)); // second choice candidate. // if there is no first choice candidate, this candidate will be chosen. // it is the candidate that we owe the least to. - peer* secondCandidate = 0; + peer* second_candidate = 0; size_type lowest_share_diff = 0; // not valid when secondCandidate==0 for (std::vector::iterator i = m_peers.begin(); @@ -502,14 +509,14 @@ namespace libtorrent if (c->is_choked()) continue; - size_type share_diff=c->share_diff(); + size_type share_diff = c->share_diff(); // select as second candidate the one that we owe the least // to - if(!secondCandidate || share_diff <= lowest_share_diff) + if(!second_candidate || share_diff <= lowest_share_diff) { lowest_share_diff = share_diff; - secondCandidate=&(*i); + second_candidate = &(*i); } // select as first candidate the one that we don't owe anything to @@ -521,8 +528,8 @@ namespace libtorrent candidate = &(*i); } } - if(candidate) return candidate; - if(secondCandidate) return secondCandidate; + if (candidate) return candidate; + if (second_candidate) return second_candidate; assert(false); return 0; } @@ -700,22 +707,25 @@ namespace libtorrent // ---------------------------- else { - // choke peers that have leeched too much without giving anything back - for (std::vector::iterator i = m_peers.begin(); - i != m_peers.end(); - ++i) + if (m_torrent->ratio() != 0) { - peer_connection* c = i->connection; - if (c == 0) continue; - - size_type diff = i->connection->share_diff(); - if (diff < -free_upload_amount - && !c->is_choked()) + // choke peers that have leeched too much without giving anything back + for (std::vector::iterator i = m_peers.begin(); + i != m_peers.end(); + ++i) { - // if we have uploaded more than a piece for free, choke peer and - // wait until we catch up with our download. - c->send_choke(); - --m_num_unchoked; + peer_connection* c = i->connection; + if (c == 0) continue; + + size_type diff = i->connection->share_diff(); + if (diff < -free_upload_amount + && !c->is_choked()) + { + // if we have uploaded more than a piece for free, choke peer and + // wait until we catch up with our download. + c->send_choke(); + --m_num_unchoked; + } } } @@ -969,7 +979,7 @@ namespace libtorrent { if (m_torrent->ratio() != 0.f) { - assert(c.share_diff() < std::numeric_limits::max()); + assert(c.share_diff() < std::numeric_limits::max()); size_type diff = c.share_diff(); if (diff > 0 && c.is_seed()) { @@ -1076,7 +1086,8 @@ namespace libtorrent // because it isn't necessary. if (m_torrent->ratio() != 0.f) { - assert(i->connection->share_diff() < std::numeric_limits::max()); + assert(i->connection->associated_torrent() == m_torrent); + assert(i->connection->share_diff() < std::numeric_limits::max()); m_available_free_upload += i->connection->share_diff(); } i->prev_amount_download += c.statistics().total_payload_download(); diff --git a/src/session.cpp b/src/session.cpp index c6abfa49d..6faa2fb87 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -662,6 +662,7 @@ namespace libtorrent { namespace detail if (t.is_aborted()) { tracker_request req = t.generate_tracker_request(); + assert(req.event == tracker_request::stopped); req.listen_port = m_listen_interface.port; req.key = m_key; m_tracker_manager.queue_request(req); @@ -876,6 +877,35 @@ namespace libtorrent m_impl.m_extension_enabled[i] = true; } + std::vector session::get_torrents() + { + std::vector ret; + { + boost::mutex::scoped_lock l(m_checker_impl.m_mutex); + for (std::deque::iterator i + = m_checker_impl.m_torrents.begin() + , end(m_checker_impl.m_torrents.end()); i != end; ++i) + { + ret.push_back(torrent_handle(&m_impl, &m_checker_impl + , i->info_hash)); + } + } + + { + boost::mutex::scoped_lock l(m_impl.m_mutex); + for (detail::session_impl::torrent_map::iterator i + = m_impl.m_torrents.begin(), end(m_impl.m_torrents.end()); + i != end; ++i) + { + if (i->second->is_aborted()) continue; + ret.push_back(torrent_handle(&m_impl, &m_checker_impl + , i->first)); + } + } + return ret; + } + + // TODO: add a check to see if filenames are accepted on the // current platform. // if the torrent already exists, this will throw duplicate_torrent @@ -1270,6 +1300,25 @@ namespace libtorrent , std::back_inserter(file_sizes) , boost::bind((mem_fun_type)&entry::integer, _1)); #endif + + if (tmp_pieces.size() == info.num_pieces() + && std::find_if(tmp_pieces.begin(), tmp_pieces.end() + , boost::bind(std::less(), _1, 0)) == tmp_pieces.end()) + { + if (info.num_files() != file_sizes.size()) + return; + + std::vector::iterator fs = file_sizes.begin(); + // the resume data says we have the entire torrent + // make sure the file sizes are the right ones + for (torrent_info::file_iterator i = info.begin_files() + , end(info.end_files()); i != end; ++i, ++fs) + { + if (i->size != *fs) return; + } + } + + if (!match_filesizes(info, save_path, file_sizes)) return; diff --git a/src/storage.cpp b/src/storage.cpp index d2a8e7de9..cd0631d3d 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -254,7 +254,8 @@ namespace libtorrent } int ret = std::rename(old_path.c_str(), new_path.c_str()); - if (ret == 0) + // This seems to return -1 even when it successfully moves the file +// if (ret == 0) { m_pimpl->save_path = save_path; return true; @@ -522,11 +523,9 @@ namespace libtorrent bool move_storage(path save_path) { - m_save_path = complete(save_path); - if (m_storage.move_storage(save_path)) { - m_save_path = save_path; + m_save_path = complete(save_path); return true; } return false; diff --git a/src/torrent.cpp b/src/torrent.cpp index 686dd44e6..28a1a9f08 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -240,6 +240,8 @@ namespace libtorrent void torrent::init() { assert(m_torrent_file.is_valid()); + assert(m_torrent_file.num_files() > 0); + assert(m_torrent_file.total_size() > 0); m_have_pieces.resize(m_torrent_file.num_pieces(), false); m_storage = std::auto_ptr(new piece_manager(m_torrent_file, m_save_path)); @@ -542,6 +544,7 @@ namespace libtorrent req.left = bytes_left(); if (req.left == -1) req.left = 1000; req.event = m_event; + m_event = tracker_request::none; req.url = m_trackers[m_currently_trying_tracker].url; req.num_want = std::max( (m_connections_quota.given @@ -743,7 +746,9 @@ namespace libtorrent bool torrent::move_storage(boost::filesystem::path const& save_path) { - return m_storage->move_storage(save_path); + bool ret = m_storage->move_storage(save_path); + m_save_path = m_storage->save_path(); + return ret; } piece_manager& torrent::filesystem() diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 7fc818d09..6c90efe61 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -197,6 +197,8 @@ namespace libtorrent { INVARIANT_CHECK; + assert(max_connections >= 2 || max_connections == -1); + call_member(m_ses, m_chk, m_info_hash , bind(&torrent::set_max_connections, _1, max_connections)); } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 9e45d90c0..dba9287c2 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -293,20 +293,14 @@ namespace libtorrent parse_info_section(info); } - boost::optional + boost::optional torrent_info::creation_date() const { - if (m_creation_date != - boost::posix_time::ptime( - boost::gregorian::date( - boost::date_time::not_a_date_time))) + if (m_creation_date != ptime(date(not_a_date_time))) { - return boost::optional(m_creation_date); + return boost::optional(m_creation_date); } - - // if there's no timestamp in the torrent file, this will return a date of january 1:st 1970. - boost::optional pt(boost::gregorian::date(1970,1,1)); - return pt; + return boost::optional(); } void torrent_info::add_tracker(std::string const& url, int tier) @@ -515,8 +509,8 @@ namespace libtorrent } if (!m_comment.empty()) os << "comment: " << m_comment << "\n"; - if (m_creation_date != boost::posix_time::ptime(boost::gregorian::date(1970, boost::gregorian::Jan, 1))) - os << "creation date: " << boost::posix_time::to_simple_string(m_creation_date) << "\n"; + if (m_creation_date != ptime(date(not_a_date_time))) + os << "creation date: " << to_simple_string(m_creation_date) << "\n"; os << "number of pieces: " << num_pieces() << "\n"; os << "piece length: " << piece_length() << "\n"; os << "files:\n";