From 007a580207a6e16f4e46ed529c8c94158060855c Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Tue, 16 Jun 2015 22:39:36 -0500 Subject: [PATCH 01/10] Options to use lowercase base32 encoding without padding --- include/libtorrent/aux_/escape_string.hpp | 15 ++++++++++++++- src/escape_string.cpp | 21 ++++++++++++++++----- test/test_string.cpp | 5 +++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/libtorrent/aux_/escape_string.hpp b/include/libtorrent/aux_/escape_string.hpp index 079a43f3d..c5d5f243f 100644 --- a/include/libtorrent/aux_/escape_string.hpp +++ b/include/libtorrent/aux_/escape_string.hpp @@ -39,6 +39,19 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + namespace string + { + enum flags_t + { + // use lower case alphabet used with i2p + lowercase = 0x1, + // don't insert padding + no_padding = 0x2, + // shortcut used for addresses as sha256 hashes + i2p = lowercase | no_padding + }; + + } TORRENT_EXTRA_EXPORT std::string unescape_string(std::string const& s, error_code& ec); // replaces all disallowed URL characters by their %-encoding TORRENT_EXTRA_EXPORT std::string escape_string(const char* str, int len); @@ -58,7 +71,7 @@ namespace libtorrent // encodes a string using the base64 scheme TORRENT_EXTRA_EXPORT std::string base64encode(std::string const& s); // encodes a string using the base32 scheme - TORRENT_EXTRA_EXPORT std::string base32encode(std::string const& s); + TORRENT_EXTRA_EXPORT std::string base32encode(std::string const& s, int flags=0); TORRENT_EXTRA_EXPORT std::string base32decode(std::string const& s); TORRENT_EXTRA_EXPORT std::string url_has_argument( diff --git a/src/escape_string.cpp b/src/escape_string.cpp index 64e3a397a..47c216955 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -321,15 +321,23 @@ namespace libtorrent return ret; } - std::string base32encode(std::string const& s) + std::string base32encode(std::string const& s, int flags) { - static const char base32_table[] = + static const char base32_table_canonical[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7' }; + static const char base32_table_lowercase[] = + { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '2', '3', '4', '5', '6', '7' + }; + const char *base32_table = 0 != (flags & string::lowercase) ? base32_table_lowercase : base32_table_canonical; int input_output_mapping[] = {0, 2, 4, 5, 7, 8}; @@ -365,10 +373,13 @@ namespace libtorrent ret += base32_table[outbuf[j]]; } - // write pad - for (int j = 0; j < 8 - num_out; ++j) + if (0 == (flags & string::no_padding)) { - ret += '='; + // write pad + for (int j = 0; j < 8 - num_out; ++j) + { + ret += '='; + } } } return ret; diff --git a/test/test_string.cpp b/test/test_string.cpp index d7d4e06a3..540b69221 100644 --- a/test/test_string.cpp +++ b/test/test_string.cpp @@ -118,6 +118,11 @@ TORRENT_TEST(string) TEST_CHECK(base32encode("fooba") == "MZXW6YTB"); TEST_CHECK(base32encode("foobar") == "MZXW6YTBOI======"); + // base32 for i2p + TEST_CHECK(base32encode("fo", string::no_padding) == "MZXQ"); + TEST_CHECK(base32encode("foob", string::i2p) == "mzxw6yq"); + TEST_CHECK(base32encode("foobar", string::lowercase) == "mzxw6ytboi======"); + TEST_CHECK(base32decode("") == ""); TEST_CHECK(base32decode("MY======") == "f"); TEST_CHECK(base32decode("MZXQ====") == "fo"); From 5d3938b39baae8ab37fb4cf8b65ce8d6ee1ab8b1 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 27 Jun 2015 17:11:50 -0500 Subject: [PATCH 02/10] Parse compact response from I2P tracker This fixes #2 --- .../libtorrent/http_tracker_connection.hpp | 6 ++- src/http_tracker_connection.cpp | 45 ++++++++++++++----- src/torrent.cpp | 36 +++++++++------ 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index b7acbaecb..a95c08a0e 100644 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -100,7 +100,11 @@ namespace libtorrent TORRENT_EXTRA_EXPORT tracker_response parse_tracker_response( char const* data, int size, error_code& ec - , bool scrape_request, sha1_hash scrape_ih); + , bool scrape_request, sha1_hash scrape_ih +#if TORRENT_USE_I2P + , bool is_i2p=false +#endif + ); TORRENT_EXTRA_EXPORT bool extract_peer_info(bdecode_node const& info , peer_entry& ret, error_code& ec); diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index a25f602a2..9ae7794bd 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -333,7 +333,11 @@ namespace libtorrent tracker_response resp = parse_tracker_response(data, size, ecode , tracker_req().kind == tracker_request::scrape_request - , tracker_req().info_hash); + , tracker_req().info_hash +#if TORRENT_USE_I2P + , tracker_req().i2pconn != NULL +#endif + ); if (!resp.warning_message.empty()) cb->tracker_warning(tracker_req(), resp.warning_message); @@ -423,7 +427,11 @@ namespace libtorrent } tracker_response parse_tracker_response(char const* data, int size, error_code& ec - , bool scrape_request, sha1_hash scrape_ih) + , bool scrape_request, sha1_hash scrape_ih +#if TORRENT_USE_I2P + , bool is_i2p +#endif + ) { tracker_response resp; @@ -499,16 +507,33 @@ namespace libtorrent { char const* peers = peers_ent.string_ptr(); int len = peers_ent.string_length(); - resp.peers4.reserve(len / 6); - for (int i = 0; i < len; i += 6) +#if TORRENT_USE_I2P + if (is_i2p) { + error_code parse_error; + for (int i = 0; i < len; i += 32) + { + if (len - i < 32) break; + peer_entry p; + p.hostname = base32encode(std::string(peers + i, 32), string::i2p); + p.hostname += ".b32.i2p"; + p.port = 6881; + resp.peers.push_back (p); + } + } + else +#endif { - if (len - i < 6) break; + resp.peers4.reserve(len / 6); + for (int i = 0; i < len; i += 6) + { + if (len - i < 6) break; - ipv4_peer_entry p; - error_code ec; - p.ip = detail::read_v4_address(peers).to_v4().to_bytes(); - p.port = detail::read_uint16(peers); - resp.peers4.push_back(p); + ipv4_peer_entry p; + error_code ec; + p.ip = detail::read_v4_address(peers).to_v4().to_bytes(); + p.port = detail::read_uint16(peers); + resp.peers4.push_back(p); + } } } else if (peers_ent && peers_ent.type() == bdecode_node::list_t) diff --git a/src/torrent.cpp b/src/torrent.cpp index 16bb9cb81..d4ed6e823 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -46,6 +46,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#if TORRENT_USE_I2P +# include +#endif #ifdef TORRENT_USE_OPENSSL #include "libtorrent/ssl_stream.hpp" @@ -3395,20 +3398,22 @@ namespace libtorrent { // this is an i2p name, we need to use the sam connection // to do the name lookup - /* - m_ses.m_i2p_conn.async_name_lookup(i->ip.c_str() - , boost::bind(&torrent::on_i2p_resolve - , shared_from_this(), _1)); - */ - // it seems like you're not supposed to do a name lookup - // on the peers returned from the tracker, but just strip - // the .i2p and use it as a destination - std::string hostname = i->hostname.substr(i->hostname.size() - 4); - torrent_state st = get_peer_list_state(); - need_peer_list(); - if (m_peer_list->add_i2p_peer(hostname.c_str(), peer_info::tracker, 0, &st)) - state_updated(); - peers_erased(st.erased); + if (boost::algorithm::ends_with(i->hostname, ".b32.i2p")) + { +#if defined TORRENT_ASIO_DEBUGGING + add_outstanding_async("torrent::on_i2p_resolve"); +#endif + r.i2pconn->async_name_lookup(i->hostname.c_str() + , boost::bind(&torrent::on_i2p_resolve + , shared_from_this(), _1, _2)); + } + else { + torrent_state st = get_peer_list_state(); + need_peer_list(); + if (m_peer_list->add_i2p_peer (i->hostname.c_str (), peer_info::tracker, 0, &st)) + state_updated (); + peers_erased (st.erased); + } } else #endif @@ -3624,6 +3629,9 @@ namespace libtorrent INVARIANT_CHECK; +#if defined TORRENT_ASIO_DEBUGGING + complete_async("torrent::on_i2p_resolve"); +#endif #ifndef TORRENT_DISABLE_LOGGING if (ec) debug_log("i2p_resolve error: %s", ec.message().c_str()); From df21a7e8cea35b739837e0bcb191e052754dc2c5 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 27 Jun 2015 16:30:00 -0500 Subject: [PATCH 03/10] Use scrape & i2p bitset flags for request --- .../libtorrent/http_tracker_connection.hpp | 6 +---- include/libtorrent/tracker_manager.hpp | 8 +++++-- src/http_tracker_connection.cpp | 24 +++++++------------ src/session_impl.cpp | 1 + src/torrent.cpp | 10 ++++---- src/udp_tracker_connection.cpp | 8 +++---- 6 files changed, 25 insertions(+), 32 deletions(-) diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index a95c08a0e..48d0be021 100644 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -100,11 +100,7 @@ namespace libtorrent TORRENT_EXTRA_EXPORT tracker_response parse_tracker_response( char const* data, int size, error_code& ec - , bool scrape_request, sha1_hash scrape_ih -#if TORRENT_USE_I2P - , bool is_i2p=false -#endif - ); + , int flags, sha1_hash scrape_ih); TORRENT_EXTRA_EXPORT bool extract_peer_info(bdecode_node const& info , peer_entry& ret, error_code& ec); diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index e8127b192..d3aaaf9f5 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -118,8 +118,12 @@ namespace libtorrent enum kind_t { - announce_request, - scrape_request + // do not compare against announce_request ! check if not scrape instead + announce_request = 0, + scrape_request = 1, + // affects interpretation of peers string in HTTP response + // see parse_tracker_response() + i2p = 2 }; std::string url; diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 9ae7794bd..7bab5c1e6 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -83,7 +83,7 @@ namespace libtorrent { std::string url = tracker_req().url; - if (tracker_req().kind == tracker_request::scrape_request) + if (0 != (tracker_req().kind & tracker_request::scrape_request)) { // find and replace "announce" with "scrape" // in request @@ -117,7 +117,7 @@ namespace libtorrent url += "info_hash="; url += escape_string((const char*)&tracker_req().info_hash[0], 20); - if (tracker_req().kind == tracker_request::announce_request) + if (0 == (tracker_req().kind & tracker_request::scrape_request)) { const char* event_string[] = {"completed", "started", "stopped", "paused"}; @@ -332,12 +332,7 @@ namespace libtorrent } tracker_response resp = parse_tracker_response(data, size, ecode - , tracker_req().kind == tracker_request::scrape_request - , tracker_req().info_hash -#if TORRENT_USE_I2P - , tracker_req().i2pconn != NULL -#endif - ); + , tracker_req().kind, tracker_req().info_hash); if (!resp.warning_message.empty()) cb->tracker_warning(tracker_req(), resp.warning_message); @@ -358,7 +353,7 @@ namespace libtorrent } // do slightly different things for scrape requests - if (tracker_req().kind == tracker_request::scrape_request) + if (0 != (tracker_req().kind & tracker_request::scrape_request)) { cb->tracker_scrape_response(tracker_req(), resp.complete , resp.incomplete, resp.downloaded, resp.downloaders); @@ -427,11 +422,7 @@ namespace libtorrent } tracker_response parse_tracker_response(char const* data, int size, error_code& ec - , bool scrape_request, sha1_hash scrape_ih -#if TORRENT_USE_I2P - , bool is_i2p -#endif - ) + , int flags, sha1_hash scrape_ih) { tracker_response resp; @@ -471,7 +462,7 @@ namespace libtorrent if (warning) resp.warning_message = warning.string_value(); - if (scrape_request) + if (0 != (flags & tracker_request::scrape_request)) { bdecode_node files = e.dict_find_dict("files"); if (!files) @@ -508,7 +499,8 @@ namespace libtorrent char const* peers = peers_ent.string_ptr(); int len = peers_ent.string_length(); #if TORRENT_USE_I2P - if (is_i2p) { + if (0 != (flags & tracker_request::i2p)) + { error_code parse_error; for (int i = 0; i < len; i += 32) { diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 5132951e0..74fd863d3 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1250,6 +1250,7 @@ namespace aux { #endif #if TORRENT_USE_I2P req.i2pconn = &m_i2p_conn; + req.kind |= tracker_request::i2p; #endif if (is_any(req.bind_ip)) req.bind_ip = m_listen_interface.address(); diff --git a/src/torrent.cpp b/src/torrent.cpp index d4ed6e823..5de9f811f 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3224,7 +3224,7 @@ namespace libtorrent req.filter = m_ip_filter; req.info_hash = m_torrent_file->info_hash(); - req.kind = tracker_request::scrape_request; + req.kind |= tracker_request::scrape_request; req.url = m_trackers[i].url; req.auth = tracker_login(); req.key = tracker_key(); @@ -3247,7 +3247,7 @@ namespace libtorrent TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; - TORRENT_ASSERT(req.kind == tracker_request::scrape_request); + TORRENT_ASSERT(0 != (req.kind & tracker_request::scrape_request)); announce_entry* ae = find_tracker(req); if (ae) @@ -3305,7 +3305,7 @@ namespace libtorrent TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; - TORRENT_ASSERT(r.kind == tracker_request::announce_request); + TORRENT_ASSERT(0 == (r.kind & tracker_request::scrape_request)); // TODO: 2 this looks suspicious. Figure out why it makes sense to use the // first IP in this list and leave a comment here @@ -11680,7 +11680,7 @@ namespace libtorrent debug_log("*** tracker error: (%d) %s %s", ec.value() , ec.message().c_str(), msg.c_str()); #endif - if (r.kind == tracker_request::announce_request) + if (0 == (r.kind & tracker_request::scrape_request)) { announce_entry* ae = find_tracker(r); if (ae) @@ -11703,7 +11703,7 @@ namespace libtorrent , ae?ae->fails:0, response_code, r.url, ec, msg); } } - else if (r.kind == tracker_request::scrape_request) + else if (0 != (r.kind & tracker_request::scrape_request)) { if (response_code == 410) { diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 1dd535d27..13e5ea39d 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -288,9 +288,9 @@ namespace libtorrent // use if if it hasn't expired if (aux::time_now() < cc->second.expires) { - if (tracker_req().kind == tracker_request::announce_request) + if (0 == (tracker_req().kind & tracker_request::scrape_request)) send_udp_announce(); - else if (tracker_req().kind == tracker_request::scrape_request) + else if (0 != (tracker_req().kind & tracker_request::scrape_request)) send_udp_scrape(); return; } @@ -468,9 +468,9 @@ namespace libtorrent cce.connection_id = connection_id; cce.expires = aux::time_now() + seconds(m_man.settings().get_int(settings_pack::udp_tracker_token_expiry)); - if (tracker_req().kind == tracker_request::announce_request) + if (0 == (tracker_req().kind & tracker_request::scrape_request)) send_udp_announce(); - else if (tracker_req().kind == tracker_request::scrape_request) + else if (0 != (tracker_req().kind & tracker_request::scrape_request)) send_udp_scrape(); return true; } From bfb3602634c91d8660a069ee0af8fabfdc750650 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 27 Jun 2015 17:12:36 -0500 Subject: [PATCH 04/10] Test compact i2p response --- test/test_tracker.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/test_tracker.cpp b/test/test_tracker.cpp index 0d84e792a..cc1f23115 100644 --- a/test/test_tracker.cpp +++ b/test/test_tracker.cpp @@ -101,6 +101,66 @@ TORRENT_TEST(parse_peers4) } } +TORRENT_TEST(parse_i2p_peers) +{ + // d8:completei8e10:incompletei4e8:intervali3600e5:peers352: ... + char const response[] = { 0x64, 0x38, 0x3a, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x69, 0x38, 0x65, 0x31, 0x30, + 0x3a, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x69, 0x34, 0x65, 0x38, 0x3a, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x69, 0x33, 0x36, 0x30, 0x30, 0x65, + 0x35, 0x3a, 0x70, 0x65, 0x65, 0x72, 0x73, 0x33, 0x35, 0x32, + 0x3a, 0xb1, 0x84, 0xe0, 0x96, 0x1f, 0xdb, 0xf2, 0xc9, 0xb0, + 0x53, 0x9a, 0x31, 0xa5, 0x35, 0xcd, 0xe8, 0x59, 0xa0, 0x7c, + 0xcd, 0xf2, 0x7c, 0x81, 0x81, 0x02, 0x11, 0x7b, 0xb4, 0x2a, + 0xd1, 0x20, 0x87, 0xd6, 0x1b, 0x06, 0x4c, 0xbb, 0x4c, 0x4e, + 0x30, 0xf9, 0xa3, 0x5d, 0x58, 0xa0, 0xa5, 0x10, 0x48, 0xfa, + 0x9b, 0x3b, 0x10, 0x86, 0x43, 0x5c, 0x2e, 0xa2, 0xa6, 0x22, + 0x31, 0xd0, 0x63, 0x6a, 0xfb, 0x4f, 0x25, 0x5b, 0xe2, 0x29, + 0xbc, 0xcc, 0xa0, 0x1a, 0x0a, 0x30, 0x45, 0x32, 0xa1, 0xc8, + 0x49, 0xf7, 0x9e, 0x03, 0xfd, 0x34, 0x80, 0x9a, 0x5b, 0xe9, + 0x78, 0x04, 0x48, 0x4e, 0xbd, 0xc0, 0x5c, 0xdd, 0x4f, 0xf8, + 0xbd, 0xc8, 0x4c, 0x4b, 0xcc, 0xf6, 0x25, 0x1b, 0xb3, 0x4d, + 0xc0, 0x91, 0xb1, 0x4b, 0xb6, 0xbd, 0x95, 0xb7, 0x8e, 0x88, + 0x79, 0xa8, 0xaa, 0x83, 0xa5, 0x7e, 0xec, 0x17, 0x60, 0x8d, + 0x1d, 0xe2, 0xbe, 0x16, 0x35, 0x83, 0x25, 0xee, 0xe4, 0xd5, + 0xbe, 0x54, 0x7b, 0xc8, 0x00, 0xdc, 0x5d, 0x56, 0xc7, 0x29, + 0xd2, 0x1e, 0x6d, 0x7a, 0xfb, 0xfc, 0xef, 0x36, 0x05, 0x8a, + 0xd0, 0xa7, 0x05, 0x4c, 0x11, 0xd5, 0x50, 0xe6, 0x2d, 0x7b, + 0xe0, 0x7d, 0x84, 0xda, 0x47, 0x48, 0x9d, 0xf9, 0x77, 0xa2, + 0xc7, 0x78, 0x90, 0xa4, 0xb5, 0x05, 0xf4, 0x95, 0xea, 0x36, + 0x7b, 0x92, 0x8c, 0x5b, 0xf7, 0x8b, 0x18, 0x94, 0x2c, 0x2f, + 0x88, 0xcf, 0xf8, 0xec, 0x5c, 0x52, 0xa8, 0x98, 0x8f, 0xd1, + 0xd3, 0xf0, 0xd8, 0x63, 0x19, 0x73, 0x33, 0xd7, 0xeb, 0x1f, + 0x87, 0x1c, 0x9f, 0x5b, 0xce, 0xe4, 0xd0, 0x15, 0x4e, 0x38, + 0xb7, 0xe3, 0xbd, 0x93, 0x64, 0xe2, 0x15, 0x3d, 0xfc, 0x56, + 0x4f, 0xd4, 0x19, 0x62, 0xe0, 0xb7, 0x59, 0x24, 0xff, 0x7f, + 0x32, 0xdf, 0x56, 0xa5, 0x62, 0x42, 0x87, 0xa3, 0x04, 0xec, + 0x09, 0x0a, 0x5b, 0x90, 0x48, 0x57, 0xc3, 0x32, 0x5f, 0x87, + 0xeb, 0xfb, 0x08, 0x69, 0x6f, 0xa9, 0x46, 0x46, 0xa9, 0x54, + 0x67, 0xec, 0x7b, 0x15, 0xc9, 0x68, 0x6b, 0x01, 0xb8, 0x10, + 0x59, 0x53, 0x9c, 0xe6, 0x1b, 0x2e, 0x70, 0x72, 0x6e, 0x82, + 0x7b, 0x03, 0xbc, 0xf2, 0x26, 0x9b, 0xb3, 0x91, 0xaa, 0xf1, + 0xba, 0x62, 0x12, 0xbb, 0x74, 0x4b, 0x70, 0x44, 0x74, 0x19, + 0xb2, 0xa1, 0x68, 0xd2, 0x30, 0xd6, 0xa5, 0x1b, 0xd9, 0xea, + 0x4d, 0xdb, 0x81, 0x8e, 0x66, 0xbf, 0x4d, 0x6c, 0x32, 0x66, + 0xc2, 0x8a, 0x22, 0x6b, 0x47, 0xc1, 0xd1, 0x52, 0x61, 0x66, + 0xa0, 0x75, 0xab, 0x65 }; + error_code ec; + tracker_response resp = parse_tracker_response(response, sizeof(response) + , ec, tracker_request::i2p, sha1_hash()); + + TEST_EQUAL(ec, error_code()); + TEST_EQUAL(resp.peers.size(), 11); + + if (resp.peers.size() == 11) + { + TEST_EQUAL(resp.peers[0].hostname, "wgcobfq73pzmtmcttiy2knon5bm2a7gn6j6idaiccf53ikwrecdq.b32.i2p"); +// TEST_EQUAL(resp.peers[9].hostname, "cbmvhhhgdmxha4toqj5qhphse2n3henk6g5geev3orfxardudgza.b32.i2p"); + TEST_EQUAL(resp.peers[10].hostname, "ufunemgwuun5t2sn3oay4zv7jvwdezwcrirgwr6b2fjgczvaowvq.b32.i2p"); + } +} + TORRENT_TEST(parse_interval) { char const response[] = "d8:intervali1042e12:min intervali10e5:peers0:e"; From fda379729c28b0bb58c48928cf78edd7cf598eeb Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 13 Jun 2015 15:45:17 -0500 Subject: [PATCH 05/10] There is no need to escape self i2p ip in Base 64 --- src/http_tracker_connection.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 7bab5c1e6..960682f9f 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -168,10 +168,7 @@ namespace libtorrent #if TORRENT_USE_I2P if (i2p && tracker_req().i2pconn) { - url += "&ip="; - url += escape_string(tracker_req().i2pconn->local_endpoint().c_str() - , tracker_req().i2pconn->local_endpoint().size()); - url += ".i2p"; + url += "&ip=" + tracker_req ().i2pconn->local_endpoint () + ".i2p"; } else #endif From 3f2e660fcf5a2353eb85d73aca5d3bd823069c53 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 20 Jun 2015 19:35:33 -0500 Subject: [PATCH 06/10] Wait for i2p acceptor before announcing This somewhat closes #1 in an ugly way --- include/libtorrent/error_code.hpp | 2 ++ src/http_tracker_connection.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index dc547664d..be13d9a0d 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -397,6 +397,8 @@ namespace libtorrent // The URL specified an i2p address, but no i2p router is configured no_i2p_router = 160, + // i2p acceptor is not available yet, can't announce without endpoint + no_i2p_endpoint = 161, diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 960682f9f..2ac1d4f95 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -168,7 +168,10 @@ namespace libtorrent #if TORRENT_USE_I2P if (i2p && tracker_req().i2pconn) { - url += "&ip=" + tracker_req ().i2pconn->local_endpoint () + ".i2p"; + if (tracker_req().i2pconn->local_endpoint().empty()) + fail(error_code(errors::no_i2p_endpoint), -1, "Waiting for i2p acceptor from SAM bridge", 5); + else + url += "&ip=" + tracker_req ().i2pconn->local_endpoint () + ".i2p"; } else #endif From 020f0816dffcdf6f7f5e02d380708060857c7466 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Wed, 24 Jun 2015 19:33:36 -0500 Subject: [PATCH 07/10] fixup! Don't break SAM connection if error occurs Propagate i2p result code, related to #3 --- src/i2p_stream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i2p_stream.cpp b/src/i2p_stream.cpp index 7a03feaea..7ec80c2ed 100644 --- a/src/i2p_stream.cpp +++ b/src/i2p_stream.cpp @@ -414,6 +414,7 @@ namespace libtorrent } } + error_code ec(result, get_i2p_category()); switch (result) { case i2p_error::no_error: @@ -421,7 +422,6 @@ namespace libtorrent break; default: { - error_code ec (result, get_i2p_category ()); handle_error (ec, h); return; } @@ -449,7 +449,7 @@ namespace libtorrent case read_connect_response: case read_session_create_response: case read_name_lookup_response: - (*h)(e); + (*h)(ec); std::vector().swap(m_buffer); break; case read_accept_response: From 70a99e6f62ac108a25740962713d2195f2f6f408 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Sat, 27 Jun 2015 17:03:03 -0500 Subject: [PATCH 08/10] Don't attempt to resolve base64 destination for i2p tracker --- include/libtorrent/http_connection.hpp | 1 + src/http_connection.cpp | 39 ++++++++++++++++---------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp index 9eb7cd598..51849bbf3 100644 --- a/include/libtorrent/http_connection.hpp +++ b/include/libtorrent/http_connection.hpp @@ -132,6 +132,7 @@ struct TORRENT_EXTRA_EXPORT http_connection private: #if TORRENT_USE_I2P + void connect_i2p_tracker(char const* destination); void on_i2p_resolve(error_code const& e , char const* destination); #endif diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 0e02ab244..4f14dfc01 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -370,11 +370,16 @@ void http_connection::start(std::string const& hostname, int port #if TORRENT_USE_I2P if (is_i2p) { + if (hostname.length() < 516) // Base64 encoded destination with optional .i2p + { #if defined TORRENT_ASIO_DEBUGGING - add_outstanding_async("http_connection::on_i2p_resolve"); + add_outstanding_async("http_connection::on_i2p_resolve"); #endif - i2p_conn->async_name_lookup(hostname.c_str(), boost::bind(&http_connection::on_i2p_resolve - , me, _1, _2)); + i2p_conn->async_name_lookup(hostname.c_str(), boost::bind(&http_connection::on_i2p_resolve + , me, _1, _2)); + } + else + connect_i2p_tracker(hostname.c_str()); } else #endif @@ -471,19 +476,8 @@ void http_connection::close(bool force) } #if TORRENT_USE_I2P -void http_connection::on_i2p_resolve(error_code const& e - , char const* destination) +void http_connection::connect_i2p_tracker(char const* destination) { -#if defined TORRENT_ASIO_DEBUGGING - complete_async("http_connection::on_i2p_resolve"); -#endif - if (e) - { - callback(e); - close(); - return; - } - #ifdef TORRENT_USE_OPENSSL TORRENT_ASSERT(m_ssl == false); TORRENT_ASSERT(m_sock.get()); @@ -502,6 +496,21 @@ void http_connection::on_i2p_resolve(error_code const& e m_sock.async_connect(tcp::endpoint(), boost::bind(&http_connection::on_connect , shared_from_this(), _1)); } + +void http_connection::on_i2p_resolve(error_code const& e + , char const* destination) +{ +#if defined TORRENT_ASIO_DEBUGGING + complete_async("http_connection::on_i2p_resolve"); +#endif + if (e) + { + callback(e); + close(); + return; + } + connect_i2p_tracker(destination); +} #endif void http_connection::on_resolve(error_code const& e From 9c489e22915c57f883e5bdb32c646c9f3466a245 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Tue, 14 Jul 2015 12:40:03 -0500 Subject: [PATCH 09/10] Don't include yourip (0.0.0.0) in i2p handshake --- src/bt_peer_connection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 69fe055bd..05a0f4dd0 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -2282,7 +2282,10 @@ namespace libtorrent std::string remote_address; std::back_insert_iterator out(remote_address); detail::write_address(remote().address(), out); - handshake["yourip"] = remote_address; +#if TORRENT_USE_I2P + if (!is_i2p(*get_socket())) +#endif + handshake["yourip"] = remote_address; handshake["reqq"] = m_settings.get_int(settings_pack::max_allowed_in_request_queue); boost::shared_ptr t = associated_torrent().lock(); TORRENT_ASSERT(t); From 2751d90368e27cec7362e279a5289de3e9800331 Mon Sep 17 00:00:00 2001 From: Mikhail Titov Date: Tue, 14 Jul 2015 14:12:23 -0500 Subject: [PATCH 10/10] Don't store 0.0.0.0 for i2p peers in resume data --- src/torrent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/torrent.cpp b/src/torrent.cpp index 5de9f811f..e3d16e183 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -7071,6 +7071,8 @@ namespace libtorrent error_code ec; torrent_peer const* p = *i; address addr = p->address(); + if (p->is_i2p_addr) + continue; if (p->banned) { #if TORRENT_USE_IPV6