From cbe3a72a6e0ea9281142b806580c33c30e7c0f89 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 27 Oct 2013 19:56:37 +0000 Subject: [PATCH] merged i2p fix from RC_0_16 --- ChangeLog | 1 + examples/client_test.cpp | 4 +- include/libtorrent/aux_/session_impl.hpp | 6 +- include/libtorrent/i2p_stream.hpp | 18 +++--- include/libtorrent/peer_info.hpp | 3 + include/libtorrent/socket_type.hpp | 5 ++ src/bt_peer_connection.cpp | 4 ++ src/i2p_stream.cpp | 76 +++++++++++++++++++----- src/peer_connection.cpp | 1 - src/policy.cpp | 7 ++- src/session_impl.cpp | 35 ++++++++++- src/socket_type.cpp | 11 ++++ 12 files changed, 136 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ccd642b9..9c9349bfd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * i2p fixes * fix issue when loading certain malformed .torrent files * pass along host header with http proxy requests and possible http_connection shutdown hang diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 7e212f85f..72b71eb9b 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -586,7 +586,9 @@ void print_peer_info(std::string& out, std::vector const& if (print_ip) { snprintf(str, sizeof(str), "%-30s %-22s", (::print_endpoint(i->ip) + - (i->connection_type == peer_info::bittorrent_utp ? " [uTP]" : "")).c_str() + (i->flags & peer_info::utp_socket ? " [uTP]" : "") + + (i->flags & peer_info::i2p_socket ? " [i2p]" : "") + ).c_str() , ::print_endpoint(i->local_endpoint).c_str()); out += str; } diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 9696aec2c..b829cbe3c 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -449,11 +449,7 @@ namespace libtorrent #endif #if TORRENT_USE_I2P - void set_i2p_proxy(proxy_settings const& s) - { - m_i2p_conn.open(s, boost::bind(&session_impl::on_i2p_open, this, _1)); - open_new_incoming_i2p_connection(); - } + void set_i2p_proxy(proxy_settings const& s); void on_i2p_open(error_code const& ec); proxy_settings const& i2p_proxy() const { return m_i2p_conn.proxy(); } diff --git a/include/libtorrent/i2p_stream.hpp b/include/libtorrent/i2p_stream.hpp index a749c9d03..92c5fc791 100644 --- a/include/libtorrent/i2p_stream.hpp +++ b/include/libtorrent/i2p_stream.hpp @@ -61,6 +61,7 @@ namespace libtorrent { invalid_id, timeout, key_not_found, + duplicated_id, num_errors }; } @@ -79,12 +80,8 @@ class i2p_stream : public proxy_base { public: - explicit i2p_stream(io_service& io_service) - : proxy_base(io_service) - , m_id(0) - , m_command(cmd_create_session) - , m_state(0) - {} + explicit i2p_stream(io_service& io_service); + ~i2p_stream(); enum command_t { @@ -159,6 +156,9 @@ private: }; int m_state; +#ifdef TORRENT_DEBUG + int m_magic; +#endif }; class i2p_connection @@ -186,11 +186,13 @@ public: private: - void on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h); + void on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h + , boost::shared_ptr); void do_name_lookup(std::string const& name , name_lookup_handler const& h); void on_name_lookup(error_code const& ec - , name_lookup_handler handler); + , name_lookup_handler handler + , boost::shared_ptr); void set_local_endpoint(error_code const& ec, char const* dest); diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index 14cb70ccc..6a7a202a5 100644 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -125,6 +125,9 @@ namespace libtorrent // happens if both peers are behind a NAT and the peers // connect via the NAT holepunch mechanism. holepunched = 0x8000, + + i2p_socket = 0x10000, + utp_socket = 0x20000, rc4_encrypted = 0x100000, plaintext_encrypted = 0x200000 }; diff --git a/include/libtorrent/socket_type.hpp b/include/libtorrent/socket_type.hpp index a34a71748..35b5f3beb 100644 --- a/include/libtorrent/socket_type.hpp +++ b/include/libtorrent/socket_type.hpp @@ -320,6 +320,11 @@ namespace libtorrent // returns true if this is a uTP socket bool is_utp(socket_type const& s); +#if TORRENT_USE_I2P + // returns true if this is an i2p socket + bool is_i2p(socket_type const& s); +#endif + // assuming the socket_type s is an ssl socket, make sure it // verifies the hostname in its SSL handshake void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec); diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 197d6be2b..803992499 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -354,6 +354,10 @@ namespace libtorrent if (has_peer_choked()) p.flags |= peer_info::remote_choked; if (support_extensions()) p.flags |= peer_info::supports_extensions; if (is_outgoing()) p.flags |= peer_info::local_connection; +#if TORRENT_USE_I2P + if (is_i2p(*get_socket())) p.flags |= peer_info::i2p_socket; +#endif + if (is_utp(*get_socket())) p.flags |= peer_info::utp_socket; #ifndef TORRENT_DISABLE_ENCRYPTION if (m_encrypted) diff --git a/src/i2p_stream.cpp b/src/i2p_stream.cpp index 19620ee17..94b342a35 100644 --- a/src/i2p_stream.cpp +++ b/src/i2p_stream.cpp @@ -64,7 +64,8 @@ namespace libtorrent "invalid key", "invalid id", "timeout", - "key not found" + "key not found", + "duplicated id" }; if (ev < 0 || ev >= i2p_error::num_errors) return "unknown error"; @@ -74,7 +75,8 @@ namespace libtorrent i2p_connection::i2p_connection(io_service& ios) : m_state(sam_idle) , m_io_service(ios) - {} + { + } i2p_connection::~i2p_connection() {} @@ -89,7 +91,8 @@ namespace libtorrent // we already seem to have a session to this SAM router if (m_sam_router.hostname == s.hostname && m_sam_router.port == s.port - && is_open()) return; + && m_sam_socket + && (is_open() || m_state == sam_connecting)) return; m_sam_router = s; m_sam_router.type = proxy_settings::i2p_proxy; @@ -112,10 +115,10 @@ namespace libtorrent add_outstanding_async("i2p_stream::on_sam_connect"); #endif m_sam_socket->async_connect(tcp::endpoint() - , boost::bind(&i2p_connection::on_sam_connect, this, _1, handler)); + , boost::bind(&i2p_connection::on_sam_connect, this, _1, handler, m_sam_socket)); } - void i2p_connection::on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h) + void i2p_connection::on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h, boost::shared_ptr) { #if defined TORRENT_ASIO_DEBUGGING complete_async("i2p_stream::on_sam_connect"); @@ -139,6 +142,7 @@ namespace libtorrent void i2p_connection::async_name_lookup(char const* name , i2p_connection::name_lookup_handler handler) { +// TORRENT_ASSERT(is_open()); if (m_state == sam_idle && m_name_lookup.empty()) do_name_lookup(name, handler); else @@ -152,12 +156,12 @@ namespace libtorrent m_state = sam_name_lookup; m_sam_socket->set_name_lookup(name.c_str()); boost::shared_ptr h(new i2p_stream::handler_type( - boost::bind(&i2p_connection::on_name_lookup, this, _1, handler))); + boost::bind(&i2p_connection::on_name_lookup, this, _1, handler, m_sam_socket))); m_sam_socket->send_name_lookup(h); } void i2p_connection::on_name_lookup(error_code const& ec - , name_lookup_handler handler) + , name_lookup_handler handler, boost::shared_ptr) { m_state = sam_idle; @@ -178,20 +182,39 @@ namespace libtorrent handler(ec, name.c_str()); } + i2p_stream::i2p_stream(io_service& io_service) + : proxy_base(io_service) + , m_id(0) + , m_command(cmd_create_session) + , m_state(0) + { +#ifdef TORRENT_DEBUG + m_magic = 0x1337; +#endif + } + + i2p_stream::~i2p_stream() + { +#ifdef TORRENT_DEBUG + TORRENT_ASSERT(m_magic == 0x1337); + m_magic = 0; +#endif + } + // TODO: move this to proxy_base and use it in all proxies bool i2p_stream::handle_error(error_code const& e, boost::shared_ptr const& h) { + TORRENT_ASSERT(m_magic == 0x1337); if (!e) return false; // fprintf(stderr, "i2p error \"%s\"\n", e.message().c_str()); (*h)(e); - error_code ec; - close(ec); return true; } void i2p_stream::do_connect(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); if (e || i == tcp::resolver::iterator()) { (*h)(e); @@ -209,6 +232,7 @@ namespace libtorrent void i2p_stream::connected(error_code const& e, boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); #if defined TORRENT_ASIO_DEBUGGING complete_async("i2p_stream::connected"); #endif @@ -223,11 +247,12 @@ namespace libtorrent #endif async_write(m_sock, asio::buffer(cmd, sizeof(cmd) - 1) , boost::bind(&i2p_stream::start_read_line, this, _1, h)); -// fputs(cmd, stderr); +// fprintf(stderr, ">>> %s", cmd); } void i2p_stream::start_read_line(error_code const& e, boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); #if defined TORRENT_ASIO_DEBUGGING complete_async("i2p_stream::start_read_line"); #endif @@ -244,7 +269,17 @@ namespace libtorrent char* string_tokenize(char* last, char sep, char** next) { if (last == 0) return 0; - *next = strchr(last, sep); + if (last[0] == '"') + { + *next = strchr(last + 1, '"'); + // consume the actual separator as well. + if (*next != NULL) + *next = strchr(*next, sep); + } + else + { + *next = strchr(last, sep); + } if (*next == 0) return last; **next = 0; ++(*next); @@ -254,6 +289,7 @@ namespace libtorrent void i2p_stream::read_line(error_code const& e, boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); #if defined TORRENT_ASIO_DEBUGGING complete_async("i2p_stream::read_line"); #endif @@ -261,7 +297,6 @@ namespace libtorrent int read_pos = m_buffer.size(); -// fprintf(stderr, "%c", m_buffer[read_pos - 1]); // look for \n which means end of the response if (m_buffer[read_pos - 1] != '\n') { @@ -318,6 +353,7 @@ namespace libtorrent break; } +// fprintf(stderr, "<<< %s\n", &m_buffer[0]); ptr = string_tokenize(next, ' ', &next); if (ptr == 0 || expect1 == 0 || strcmp(expect1, ptr)) { handle_error(invalid_response, h); return; } ptr = string_tokenize(next, ' ', &next); @@ -331,8 +367,10 @@ namespace libtorrent { char* name = string_tokenize(next, '=', &next); if (name == 0) break; +// fprintf(stderr, "name=\"%s\"\n", name); char* ptr = string_tokenize(next, ' ', &next); if (ptr == 0) { handle_error(invalid_response, h); return; } +// fprintf(stderr, "value=\"%s\"\n", ptr); if (strcmp("RESULT", name) == 0) { @@ -350,6 +388,8 @@ namespace libtorrent result = i2p_error::timeout; else if (strcmp("KEY_NOT_FOUND", ptr) == 0) result = i2p_error::key_not_found; + else if (strcmp("DUPLICATED_ID", ptr) == 0) + result = i2p_error::duplicated_id; else result = i2p_error::num_errors; // unknown error } @@ -423,11 +463,12 @@ namespace libtorrent void i2p_stream::send_connect(boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); m_state = read_connect_response; char cmd[1024]; int size = snprintf(cmd, sizeof(cmd), "STREAM CONNECT ID=%s DESTINATION=%s\n" , m_id, m_dest.c_str()); -// fputs(cmd, stderr); +// fprintf(stderr, ">>> %s", cmd); #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("i2p_stream::start_read_line"); #endif @@ -437,10 +478,11 @@ namespace libtorrent void i2p_stream::send_accept(boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); m_state = read_accept_response; char cmd[400]; int size = snprintf(cmd, sizeof(cmd), "STREAM ACCEPT ID=%s\n", m_id); -// fputs(cmd, stderr); +// fprintf(stderr, ">>> %s", cmd); #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("i2p_stream::start_read_line"); #endif @@ -450,11 +492,12 @@ namespace libtorrent void i2p_stream::send_session_create(boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); m_state = read_session_create_response; char cmd[400]; int size = snprintf(cmd, sizeof(cmd), "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT\n" , m_id); -// fputs(cmd, stderr); +// fprintf(stderr, ">>> %s", cmd); #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("i2p_stream::start_read_line"); #endif @@ -464,10 +507,11 @@ namespace libtorrent void i2p_stream::send_name_lookup(boost::shared_ptr h) { + TORRENT_ASSERT(m_magic == 0x1337); m_state = read_name_lookup_response; char cmd[1024]; int size = snprintf(cmd, sizeof(cmd), "NAMING LOOKUP NAME=%s\n", m_name_lookup.c_str()); -// fputs(cmd, stderr); +// fprintf(stderr, ">>> %s", cmd); #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("i2p_stream::start_read_line"); #endif diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index ecd1b17b2..6aebdf1bf 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -475,7 +475,6 @@ namespace libtorrent disconnect(ec); return; } - TORRENT_ASSERT(m_remote.address() != address_v4::any()); if (m_remote.address().is_v4()) { m_socket->set_option(type_of_service(m_ses.settings().peer_tos), ec); diff --git a/src/policy.cpp b/src/policy.cpp index 7d9996697..5ea55872f 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -1190,8 +1190,11 @@ namespace libtorrent #ifdef TORRENT_DEBUG else { - std::pair range = find_peers(p->address()); - TORRENT_ASSERT(range.second - range.first == 1); + if (!p->is_i2p_addr) + { + std::pair range = find_peers(p->address()); + TORRENT_ASSERT(range.second - range.first == 1); + } } #endif diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 98bb7f18f..9152bf109 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2618,8 +2618,41 @@ retry: } #if TORRENT_USE_I2P + void session_impl::set_i2p_proxy(proxy_settings const& s) + { +#if defined TORRENT_ASIO_DEBUGGING + add_outstanding_async("session_impl::on_i2p_open"); +#endif + // we need this socket to be open before we + // can make name lookups for trackers for instance. + // pause the session now and resume it once we've + // established the i2p SAM connection + pause(); + m_i2p_conn.open(s, boost::bind(&session_impl::on_i2p_open, this, _1)); + open_new_incoming_i2p_connection(); + } + void session_impl::on_i2p_open(error_code const& ec) { +#if defined TORRENT_ASIO_DEBUGGING + complete_async("session_impl::on_i2p_open"); +#endif + if (ec) + { +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + char msg[200]; + snprintf(msg, sizeof(msg), "i2p open failed (%d) %s", ec.value(), ec.message().c_str()); + (*m_logger) << msg << "\n"; +#endif + } + else + { + // now that we have our i2p connection established + // it's OK to start torrents and use this socket to + // do i2p name lookups + resume(); + } + open_new_incoming_i2p_connection(); } @@ -2889,8 +2922,6 @@ retry: return; } - TORRENT_ASSERT(endp.address() != address_v4::any()); - #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) session_log(" <== INCOMING CONNECTION %s type: %s" , print_endpoint(endp).c_str(), s->type_name()); diff --git a/src/socket_type.cpp b/src/socket_type.cpp index abd061d87..f1701d031 100644 --- a/src/socket_type.cpp +++ b/src/socket_type.cpp @@ -72,6 +72,17 @@ namespace libtorrent ; } +#if TORRENT_USE_I2P + bool is_i2p(socket_type const& s) + { + return s.get() +#ifdef TORRENT_USE_OPENSSL + || s.get >() +#endif + ; + } +#endif + void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec) { #if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700