From f16d0b79532b3b69b109e88fdb9456c7bfb37ecf Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 23 Oct 2016 22:01:09 -0400 Subject: [PATCH 1/5] add unit test for 'file_sizes' entry in resume data (#1248) add unit test for 'file_sizes' entry in resume data. fix resume data bug in client_test for magnet links and minor resume data cleanup in default_storage --- examples/client_test.cpp | 2 +- src/storage.cpp | 37 ++++++++++++++++++------ test/test_resume.cpp | 61 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index c3b462cb1..fa5f328da 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1024,7 +1024,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a save_file(filename, buffer); files.insert(std::pair(filename, h)); - hash_to_filename.insert(std::make_pair(hash, filename)); + hash_to_filename[hash] = filename; non_files.erase(h); } } diff --git a/src/storage.cpp b/src/storage.cpp index 18cd4f641..64091f732 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -515,9 +515,9 @@ namespace libtorrent // don't do full file allocations on network drives #if TORRENT_USE_WSTRING std::wstring f = convert_to_wstring(m_save_path); - int drive_type = GetDriveTypeW(f.c_str()); + int const drive_type = GetDriveTypeW(f.c_str()); #else - int drive_type = GetDriveTypeA(m_save_path.c_str()); + int const drive_type = GetDriveTypeA(m_save_path.c_str()); #endif if (drive_type == DRIVE_REMOTE) @@ -581,7 +581,7 @@ namespace libtorrent | file::random_access, ec); if (ec) return; - boost::int64_t size = files().file_size(file_index); + boost::int64_t const size = files().file_size(file_index); f->set_size(size, ec.ec); if (ec) { @@ -589,7 +589,7 @@ namespace libtorrent ec.operation = storage_error::fallocate; break; } - size_t mtime = m_stat_cache.get_filetime(file_index); + size_t const mtime = m_stat_cache.get_filetime(file_index); m_stat_cache.set_cache(file_index, size, mtime); } ec.ec.clear(); @@ -621,12 +621,15 @@ namespace libtorrent file_path = files().file_path(i, m_save_path); stat_file(file_path, &s, ec.ec); boost::int64_t r = s.file_size; - if (ec.ec || !(s.mode & file_status::regular_file)) r = -1; + if (ec.ec || !(s.mode & file_status::regular_file)) + { + r = stat_cache::cache_error; + } if (ec && ec.ec == boost::system::errc::no_such_file_or_directory) { ec.ec.clear(); - r = -3; + r = stat_cache::no_exist; } m_stat_cache.set_cache(i, r, s.mtime); @@ -865,7 +868,7 @@ namespace libtorrent { boost::int64_t file_size = 0; time_t file_time = 0; - boost::int64_t cache_state = m_stat_cache.get_filesize(i); + boost::int64_t const cache_state = m_stat_cache.get_filesize(i); if (cache_state != stat_cache::not_in_cache) { if (cache_state >= 0) @@ -883,6 +886,7 @@ namespace libtorrent { file_size = s.file_size; file_time = s.mtime; + m_stat_cache.set_cache(i, file_size, file_time); } else if (error == error_code(boost::system::errc::no_such_file_or_directory , generic_category())) @@ -897,6 +901,21 @@ namespace libtorrent m_stat_cache.set_error(i); } } +#if TORRENT_USE_INVARIANT_CHECKS + { + file_status s; + error_code error; + stat_file(fs.file_path(i, m_save_path), &s, error); + if (s.file_size >= 0 && !error) + { + TORRENT_ASSERT(s.file_size == file_size); + } + else + { + TORRENT_ASSERT(file_size == 0); + } + } +#endif fl.push_back(entry(entry::list_t)); entry::list_type& p = fl.back().list(); @@ -1454,7 +1473,8 @@ namespace libtorrent if (m_file_created[file] == false) { error_code e; - h->set_size(files().file_size(file), e); + boost::int64_t const size = files().file_size(file); + h->set_size(size, e); m_file_created.set_bit(file); if (e) { @@ -1463,6 +1483,7 @@ namespace libtorrent ec.operation = storage_error::fallocate; return h; } + m_stat_cache.set_dirty(file); } } return h; diff --git a/test/test_resume.cpp b/test/test_resume.cpp index 4f6ef334f..de871d33a 100644 --- a/test/test_resume.cpp +++ b/test/test_resume.cpp @@ -192,6 +192,63 @@ void default_tests(torrent_status const& s) TEST_EQUAL(s.completed_time, 1348); } +void test_file_sizes(bool allocate) +{ + error_code ec; + remove_all("test_resume", ec); + + lt::settings_pack pack = settings(); + // we're not testing the hash check, just accept the data we write + pack.set_bool(settings_pack::disable_hash_checks, true); + lt::session ses(pack); + boost::shared_ptr ti = generate_torrent(); + add_torrent_params p; + p.ti = ti; + p.save_path = "."; + if (allocate) p.storage_mode = storage_mode_allocate; + torrent_handle h = ses.add_torrent(p); + + wait_for_downloading(ses, "ses"); + + std::vector piece(ti->piece_length(), 0); + h.add_piece(0, piece.data()); + + h.save_resume_data(); + alert const* a = wait_for_alert(ses, save_resume_data_alert::alert_type); + TEST_CHECK(a); + + save_resume_data_alert const* ra = alert_cast(a); + TEST_CHECK(ra); + if (ra) + { + fprintf(stderr, "%s\n", ra->resume_data->to_string().c_str()); + bool const has_file_sizes = ra->resume_data->dict().count("file sizes") == 1; + TEST_CHECK(has_file_sizes); + if (!has_file_sizes) return; + // { 'file sizes': [ [ size, timestamp], [...], ... ] } + boost::int64_t const file_size = (*ra->resume_data)["file sizes"].list() + .front().list().front().integer(); + if (allocate) + { + TEST_EQUAL(file_size, ti->files().file_size(0)); + } + else + { + TEST_EQUAL(file_size, ti->piece_length()); + } + } +} + +TORRENT_TEST(file_sizes_allocate) +{ + test_file_sizes(true); +} + +TORRENT_TEST(file_sizes) +{ + test_file_sizes(false); +} + TORRENT_TEST(piece_priorities) { lt::session ses(settings()); @@ -208,7 +265,9 @@ TORRENT_TEST(piece_priorities) alert const* a = wait_for_alert(ses, save_resume_data_alert::alert_type); TEST_CHECK(a); - if (save_resume_data_alert const* ra = alert_cast(a)) + save_resume_data_alert const* ra = alert_cast(a); + TEST_CHECK(ra); + if (ra) { fprintf(stderr, "%s\n", ra->resume_data->to_string().c_str()); entry::string_type prios = (*ra->resume_data)["piece_priority"].string(); From 241e9fd25a4e2ab15b5eb535e74f00cf10b151ae Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Mon, 24 Oct 2016 20:48:57 -0700 Subject: [PATCH 2/5] add assert to detect index out-of-range --- src/disk_io_thread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 07c1089e6..5859022b4 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -334,6 +334,8 @@ namespace libtorrent end = int(p->blocks_in_piece); } + TORRENT_ASSERT(end <= p->blocks_in_piece); + // count number of blocks that would be flushed int num_blocks = 0; for (int i = end-1; i >= 0; --i) From f36b9a805ae12c53a348ccd39715bad5b22e0b2b Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Mon, 24 Oct 2016 21:13:35 -0700 Subject: [PATCH 3/5] avoid concurrent access to hash offset Since partial_hash::offset is not an atomic it is technically UD to access it concurrently from multiple threads. --- src/disk_io_thread.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 5859022b4..a1a30985a 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -2153,6 +2153,9 @@ namespace libtorrent DLOG("kick_hasher: %d - %d (piece: %d offset: %d)\n" , cursor, end, int(pe->piece), ph->offset); + // save a local copy of offset to avoid concurrent access + int offset = ph->offset; + l.unlock(); time_point start_time = clock_type::now(); @@ -2160,15 +2163,17 @@ namespace libtorrent for (int i = cursor; i < end; ++i) { cached_block_entry& bl = pe->blocks[i]; - int size = (std::min)(block_size, piece_size - ph->offset); + int size = (std::min)(block_size, piece_size - offset); ph->h.update(bl.buf, size); - ph->offset += size; + offset += size; } boost::uint64_t hash_time = total_microseconds(clock_type::now() - start_time); l.lock(); + ph->offset = offset; + TORRENT_PIECE_ASSERT(pe->hashing, pe); TORRENT_PIECE_ASSERT(pe->hash, pe); @@ -2388,22 +2393,25 @@ namespace libtorrent // to keep the cache footprint low, try to evict a volatile piece m_disk_cache.try_evict_one_volatile(); + // save a local copy of offset to avoid concurrent access + int offset = ph->offset; + l.unlock(); int ret = 0; int next_locked_block = 0; - for (int i = ph->offset / block_size; i < blocks_in_piece; ++i) + for (int i = offset / block_size; i < blocks_in_piece; ++i) { file::iovec_t iov; - iov.iov_len = (std::min)(block_size, piece_size - ph->offset); + iov.iov_len = (std::min)(block_size, piece_size - offset); if (next_locked_block < num_locked_blocks && locked_blocks[next_locked_block] == i) { ++next_locked_block; TORRENT_PIECE_ASSERT(pe->blocks[i].buf, pe); - TORRENT_PIECE_ASSERT(ph->offset == i * block_size, pe); - ph->offset += iov.iov_len; + TORRENT_PIECE_ASSERT(offset == i * block_size, pe); + offset += iov.iov_len; ph->h.update(pe->blocks[i].buf, iov.iov_len); } else @@ -2436,9 +2444,9 @@ namespace libtorrent time_point start_time = clock_type::now(); - TORRENT_PIECE_ASSERT(ph->offset == i * block_size, pe); + TORRENT_PIECE_ASSERT(offset == i * block_size, pe); ret = j->storage->get_storage_impl()->readv(&iov, 1, j->piece - , ph->offset, file_flags, j->error); + , offset, file_flags, j->error); if (ret < 0) { @@ -2474,8 +2482,8 @@ namespace libtorrent m_stats_counters.inc_stats_counter(counters::disk_job_time, read_time); } - TORRENT_PIECE_ASSERT(ph->offset == i * block_size, pe); - ph->offset += iov.iov_len; + TORRENT_PIECE_ASSERT(offset == i * block_size, pe); + offset += iov.iov_len; ph->h.update(static_cast(iov.iov_base), iov.iov_len); l.lock(); @@ -2486,6 +2494,8 @@ namespace libtorrent l.lock(); + ph->offset = offset; + // decrement the refcounts of the blocks we just hashed for (int i = 0; i < num_locked_blocks; ++i) m_disk_cache.dec_block_refcount(pe, locked_blocks[i], block_cache::ref_hashing); From cf7db392b6712e6076abe6e25ba283457680cb29 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Mon, 24 Oct 2016 22:02:44 -0700 Subject: [PATCH 4/5] assert that offset didn't change while hashing --- src/disk_io_thread.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index a1a30985a..64be2ebc3 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -2155,6 +2155,9 @@ namespace libtorrent // save a local copy of offset to avoid concurrent access int offset = ph->offset; +#if TORRENT_USE_ASSERTS + int old_offset = offset; +#endif l.unlock(); @@ -2172,6 +2175,7 @@ namespace libtorrent l.lock(); + TORRENT_ASSERT(old_offset == ph->offset); ph->offset = offset; TORRENT_PIECE_ASSERT(pe->hashing, pe); @@ -2395,6 +2399,9 @@ namespace libtorrent // save a local copy of offset to avoid concurrent access int offset = ph->offset; +#if TORRENT_USE_ASSERTS + int old_offset = offset; +#endif l.unlock(); @@ -2494,6 +2501,7 @@ namespace libtorrent l.lock(); + TORRENT_ASSERT(old_offset == ph->offset); ph->offset = offset; // decrement the refcounts of the blocks we just hashed From 61af222d92299b388f502b5c61305b709be410bf Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Tue, 25 Oct 2016 08:03:26 -0400 Subject: [PATCH 5/5] add utility function for generating peer ID fingerprint (#1249) add utility function for generating peer ID fingerprint --- CMakeLists.txt | 1 + ChangeLog | 1 + Jamfile | 1 + bindings/python/src/fingerprint.cpp | 2 + include/libtorrent/fingerprint.hpp | 107 +++++++++---------------- include/libtorrent/identify_client.hpp | 29 +++++-- include/libtorrent/session.hpp | 14 ++++ include/libtorrent/settings_pack.hpp | 5 +- src/Makefile.am | 1 + src/bt_peer_connection.cpp | 3 +- src/fingerprint.cpp | 100 +++++++++++++++++++++++ src/identify_client.cpp | 10 ++- test/test_primitives.cpp | 8 ++ 13 files changed, 202 insertions(+), 80 deletions(-) create mode 100644 src/fingerprint.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 37c2ad28e..e9df1478b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(sources escape_string string_util file + fingerprint gzip hasher hex diff --git a/ChangeLog b/ChangeLog index 75c2b5cfc..9851584c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * add utility function for generating peer ID fingerprint * fix bug in last-seen-complete * remove file size limit in torrent_info filename constructor * fix tail-padding for last file in create_torrent diff --git a/Jamfile b/Jamfile index 31a2023cc..5580ccf91 100644 --- a/Jamfile +++ b/Jamfile @@ -582,6 +582,7 @@ SOURCES = escape_string string_util file + fingerprint gzip hasher hex diff --git a/bindings/python/src/fingerprint.cpp b/bindings/python/src/fingerprint.cpp index 27215fac4..b079ef3c5 100644 --- a/bindings/python/src/fingerprint.cpp +++ b/bindings/python/src/fingerprint.cpp @@ -10,6 +10,7 @@ void bind_fingerprint() using namespace boost::python; using namespace libtorrent; +#ifndef TORRENT_NO_DEPRECATE class_("fingerprint", no_init) .def( init( @@ -23,5 +24,6 @@ void bind_fingerprint() .def_readonly("revision_version", &fingerprint::revision_version) .def_readonly("tag_version", &fingerprint::tag_version) ; +#endif } diff --git a/include/libtorrent/fingerprint.hpp b/include/libtorrent/fingerprint.hpp index 78f302661..371c7fb3a 100644 --- a/include/libtorrent/fingerprint.hpp +++ b/include/libtorrent/fingerprint.hpp @@ -38,90 +38,61 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/peer_id.hpp" -#include "libtorrent/assert.hpp" #include "libtorrent/export.hpp" namespace libtorrent { + // This is a utility function to produce a client ID fingerprint formatted to + // the most common convention. + // + // The name string should contain exactly two characters. These are the + // characters unique to your client, used to identify it. Make sure not to + // clash with anybody else. Here are some taken id's: + // + // +----------+-----------------------+ + // | id chars | client | + // +==========+=======================+ + // | 'AZ' | Azureus | + // +----------+-----------------------+ + // | 'LT' | libtorrent (default) | + // +----------+-----------------------+ + // | 'BX' | BittorrentX | + // +----------+-----------------------+ + // | 'MT' | Moonlight Torrent | + // +----------+-----------------------+ + // | 'TS' | Torrent Storm | + // +----------+-----------------------+ + // | 'SS' | Swarm Scope | + // +----------+-----------------------+ + // | 'XT' | Xan Torrent | + // +----------+-----------------------+ + // + // There's an informal directory of client id's here_. + // + // .. _here: http://wiki.theory.org/BitTorrentSpecification#peer_id + // + // The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to + // identify the version of your client. + TORRENT_EXPORT std::string generate_fingerprint(std::string name + , int major, int minor = 0, int revision = 0, int tag = 0); + // The fingerprint class represents information about a client and its version. It is used // to encode this information into the client's peer id. - struct TORRENT_DEPRECATED_EXPORT fingerprint + struct TORRENT_DEPRECATED TORRENT_DEPRECATED_EXPORT fingerprint { + fingerprint(const char* id_string, int major, int minor, int revision, int tag); - // The constructor takes a ``char const*`` that should point to a string constant containing - // exactly two characters. These are the characters that should be unique for your client. Make - // sure not to clash with anybody else. Here are some taken id's: - // - // +----------+-----------------------+ - // | id chars | client | - // +==========+=======================+ - // | 'AZ' | Azureus | - // +----------+-----------------------+ - // | 'LT' | libtorrent (default) | - // +----------+-----------------------+ - // | 'BX' | BittorrentX | - // +----------+-----------------------+ - // | 'MT' | Moonlight Torrent | - // +----------+-----------------------+ - // | 'TS' | Torrent Storm | - // +----------+-----------------------+ - // | 'SS' | Swarm Scope | - // +----------+-----------------------+ - // | 'XT' | Xan Torrent | - // +----------+-----------------------+ - // - // There's an informal directory of client id's here_. - // - // .. _here: http://wiki.theory.org/BitTorrentSpecification#peer_id - // - // The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to identify the - // version of your client. - fingerprint(const char* id_string, int major, int minor, int revision, int tag) - : major_version(major) - , minor_version(minor) - , revision_version(revision) - , tag_version(tag) - { - TORRENT_ASSERT(id_string); - TORRENT_ASSERT(major >= 0); - TORRENT_ASSERT(minor >= 0); - TORRENT_ASSERT(revision >= 0); - TORRENT_ASSERT(tag >= 0); - TORRENT_ASSERT(std::strlen(id_string) == 2); - name[0] = id_string[0]; - name[1] = id_string[1]; - } - +#ifndef TORRENT_NO_DEPRECATE // generates the actual string put in the peer-id, and return it. - std::string to_string() const - { - char s[100]; - snprintf(s, 100, "-%c%c%c%c%c%c-" - , name[0], name[1] - , version_to_char(major_version) - , version_to_char(minor_version) - , version_to_char(revision_version) - , version_to_char(tag_version)); - return s; - } + std::string to_string() const; +#endif char name[2]; int major_version; int minor_version; int revision_version; int tag_version; - - private: - - char version_to_char(int v) const - { - if (v >= 0 && v < 10) return char('0' + v); - else if (v >= 10) return char('A' + (v - 10)); - TORRENT_ASSERT(false); - return '0'; - } - }; } diff --git a/include/libtorrent/identify_client.hpp b/include/libtorrent/identify_client.hpp index e1816a7d5..d038f97ab 100644 --- a/include/libtorrent/identify_client.hpp +++ b/include/libtorrent/identify_client.hpp @@ -35,21 +35,19 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" +#ifndef TORRENT_NO_DEPRECATE #include "libtorrent/aux_/disable_warnings_push.hpp" - #include - #include "libtorrent/aux_/disable_warnings_pop.hpp" +#endif #include "libtorrent/peer_id.hpp" #include "libtorrent/fingerprint.hpp" +// TODO: hide this declaration when deprecated functions are disabled, and +// remove its internal use namespace libtorrent { - - // TODO: hide these declarations when deprecaated functions are disabled, and - // expose them internally in a header under aux_. - // these functions don't really need to be public. This mechanism of // advertising client software and version is also out-dated. @@ -59,6 +57,16 @@ namespace libtorrent TORRENT_DEPRECATED_EXPORT TORRENT_DEPRECATED std::string identify_client(const peer_id& p); +#ifndef TORRENT_NO_DEPRECATE + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // Returns an optional fingerprint if any can be identified from the peer // id. This can be used to automate the identification of clients. It will // not be able to identify peers with non- standard encodings. Only Azureus @@ -67,6 +75,15 @@ namespace libtorrent boost::optional client_fingerprint(peer_id const& p); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif // TORRENT_NO_DEPRECATE + } #endif // TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index f16f41e15..6a0476d3a 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -201,6 +201,14 @@ namespace libtorrent } #ifndef TORRENT_NO_DEPRECATE +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif TORRENT_DEPRECATED session(fingerprint const& print , int flags = start_default_features | add_default_plugins @@ -253,6 +261,12 @@ namespace libtorrent } start(flags, pack, NULL); } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #endif // TORRENT_NO_DEPRECATE // The destructor of session will notify all trackers that our torrents diff --git a/include/libtorrent/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index 6776de8c3..1608083ac 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -201,7 +201,10 @@ namespace libtorrent // this is the fingerprint for the client. It will be used as the // prefix to the peer_id. If this is 20 bytes (or longer) it will be - // used as the peer-id + // truncated at 20 bytes and used as the entire peer-id + // + // There is a utility function, generate_fingerprint() that can be used + // to generate a standard client peer ID fingerprint prefix. peer_fingerprint, // This is a comma-separated list of IP port-pairs. They will be added diff --git a/src/Makefile.am b/src/Makefile.am index f273f90fe..70ffc0bd4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,7 @@ libtorrent_rasterbar_la_SOURCES = \ file.cpp \ file_pool.cpp \ file_storage.cpp \ + fingerprint.cpp \ gzip.cpp \ hasher.cpp \ hex.cpp \ diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index d99f9905c..e04e61801 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -3405,8 +3405,7 @@ namespace libtorrent } m_client_version = identify_client(pid); - boost::optional f = client_fingerprint(pid); - if (f && std::equal(f->name, f->name + 2, "BC")) + if (pid[0] == '-' && pid[1] == 'B' && pid[2] == 'C' && pid[7] == '-') { // if this is a bitcomet client, lower the request queue size limit if (max_out_request_queue() > 50) max_out_request_queue(50); diff --git a/src/fingerprint.cpp b/src/fingerprint.cpp new file mode 100644 index 000000000..763f61833 --- /dev/null +++ b/src/fingerprint.cpp @@ -0,0 +1,100 @@ +/* + +Copyright (c) 2016, 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. + +*/ + +#include "libtorrent/fingerprint.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent { + namespace { + + char version_to_char(int const v) + { + if (v >= 0 && v < 10) return char('0' + v); + else if (v >= 10) return char('A' + (v - 10)); + TORRENT_ASSERT(false); + return '0'; + } + + } // anonymous namespace + + std::string generate_fingerprint(std::string name, int const major + , int const minor + , int const revision + , int const tag) + { + TORRENT_ASSERT_PRECOND(major >= 0); + TORRENT_ASSERT_PRECOND(minor >= 0); + TORRENT_ASSERT_PRECOND(revision >= 0); + TORRENT_ASSERT_PRECOND(tag >= 0); + TORRENT_ASSERT_PRECOND(name.size() == 2); + if (name.size() < 2) name = "--"; + + std::string ret; + ret.resize(8); + ret[0] = '-'; + ret[1] = name[0]; + ret[2] = name[1]; + ret[3] = version_to_char(major); + ret[4] = version_to_char(minor); + ret[5] = version_to_char(revision); + ret[6] = version_to_char(tag); + ret[7] = '-'; + return ret; + } + + fingerprint::fingerprint(const char* id_string, int major, int minor + , int revision, int tag) + : major_version(major) + , minor_version(minor) + , revision_version(revision) + , tag_version(tag) + { + TORRENT_ASSERT(id_string); + TORRENT_ASSERT(major >= 0); + TORRENT_ASSERT(minor >= 0); + TORRENT_ASSERT(revision >= 0); + TORRENT_ASSERT(tag >= 0); + TORRENT_ASSERT(std::strlen(id_string) == 2); + name[0] = id_string[0]; + name[1] = id_string[1]; + } + +#ifndef TORRENT_NO_DEPRECATE + std::string fingerprint::to_string() const + { + return generate_fingerprint(name, major_version, minor_version + , revision_version, tag_version); + } +#endif // TORRENT_NO_DEPRECATE + +} + diff --git a/src/identify_client.cpp b/src/identify_client.cpp index a04444be0..6748431ca 100644 --- a/src/identify_client.cpp +++ b/src/identify_client.cpp @@ -35,9 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/aux_/disable_warnings_push.hpp" - #include - #include "libtorrent/aux_/disable_warnings_pop.hpp" #include "libtorrent/identify_client.hpp" @@ -141,7 +139,9 @@ namespace // must be ordered alphabetically map_entry name_map[] = { - {"A", "ABC"} + {"7T", "aTorrent for android"} + , {"A", "ABC"} + , {"AB", "AnyEvent BitTorrent"} , {"AG", "Ares"} , {"AR", "Arctic Torrent"} , {"AT", "Artemis"} @@ -343,6 +343,8 @@ namespace namespace libtorrent { +#ifndef TORRENT_NO_DEPRECATE + boost::optional client_fingerprint(peer_id const& p) { // look for azureus style id @@ -360,6 +362,8 @@ namespace libtorrent return f; } +#endif + std::string identify_client(peer_id const& p) { char const* PID = p.data(); diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index ee5ff0d81..e1282f1c3 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" #include "libtorrent/socket_io.hpp" // for print_endpoint #include "libtorrent/announce_entry.hpp" +#include "libtorrent/fingerprint.hpp" #include "test.hpp" #include "setup_transfer.hpp" @@ -159,5 +160,12 @@ TORRENT_TEST(primitives) // test endpoint_to_bytes TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("10.11.12.13"), 8080)), "\x0a\x0b\x0c\x0d\x1f\x90"); TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("16.5.127.1"), 12345)), "\x10\x05\x7f\x01\x30\x39"); + + // test gen_fingerprint + TEST_EQUAL(generate_fingerprint("AB", 1, 2, 3, 4), "-AB1234-"); + TEST_EQUAL(generate_fingerprint("AB", 1, 2), "-AB1200-"); + TEST_EQUAL(generate_fingerprint("..", 1, 10), "-..1A00-"); + TEST_EQUAL(generate_fingerprint("CZ", 1, 15), "-CZ1F00-"); + TEST_EQUAL(generate_fingerprint("CZ", 1, 15, 16, 17), "-CZ1FGH-"); }