merged i2p fix from RC_0_16

This commit is contained in:
Arvid Norberg 2013-10-27 19:56:37 +00:00
parent 1d55894bef
commit cbe3a72a6e
12 changed files with 136 additions and 35 deletions

View File

@ -25,6 +25,7 @@
* fix uTP edge case where udp socket buffer fills up * fix uTP edge case where udp socket buffer fills up
* fix nagle implementation in uTP * fix nagle implementation in uTP
* i2p fixes
* fix issue when loading certain malformed .torrent files * fix issue when loading certain malformed .torrent files
* pass along host header with http proxy requests and possible http_connection shutdown hang * pass along host header with http proxy requests and possible http_connection shutdown hang

View File

@ -586,7 +586,9 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
if (print_ip) if (print_ip)
{ {
snprintf(str, sizeof(str), "%-30s %-22s", (::print_endpoint(i->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()); , ::print_endpoint(i->local_endpoint).c_str());
out += str; out += str;
} }

View File

@ -449,11 +449,7 @@ namespace libtorrent
#endif #endif
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
void set_i2p_proxy(proxy_settings const& s) 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 on_i2p_open(error_code const& ec); void on_i2p_open(error_code const& ec);
proxy_settings const& i2p_proxy() const proxy_settings const& i2p_proxy() const
{ return m_i2p_conn.proxy(); } { return m_i2p_conn.proxy(); }

View File

@ -61,6 +61,7 @@ namespace libtorrent {
invalid_id, invalid_id,
timeout, timeout,
key_not_found, key_not_found,
duplicated_id,
num_errors num_errors
}; };
} }
@ -79,12 +80,8 @@ class i2p_stream : public proxy_base
{ {
public: public:
explicit i2p_stream(io_service& io_service) explicit i2p_stream(io_service& io_service);
: proxy_base(io_service) ~i2p_stream();
, m_id(0)
, m_command(cmd_create_session)
, m_state(0)
{}
enum command_t enum command_t
{ {
@ -159,6 +156,9 @@ private:
}; };
int m_state; int m_state;
#ifdef TORRENT_DEBUG
int m_magic;
#endif
}; };
class i2p_connection class i2p_connection
@ -186,11 +186,13 @@ public:
private: 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<i2p_stream>);
void do_name_lookup(std::string const& name void do_name_lookup(std::string const& name
, name_lookup_handler const& h); , name_lookup_handler const& h);
void on_name_lookup(error_code const& ec void on_name_lookup(error_code const& ec
, name_lookup_handler handler); , name_lookup_handler handler
, boost::shared_ptr<i2p_stream>);
void set_local_endpoint(error_code const& ec, char const* dest); void set_local_endpoint(error_code const& ec, char const* dest);

View File

@ -125,6 +125,9 @@ namespace libtorrent
// happens if both peers are behind a NAT and the peers // happens if both peers are behind a NAT and the peers
// connect via the NAT holepunch mechanism. // connect via the NAT holepunch mechanism.
holepunched = 0x8000, holepunched = 0x8000,
i2p_socket = 0x10000,
utp_socket = 0x20000,
rc4_encrypted = 0x100000, rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000 plaintext_encrypted = 0x200000
}; };

View File

@ -320,6 +320,11 @@ namespace libtorrent
// returns true if this is a uTP socket // returns true if this is a uTP socket
bool is_utp(socket_type const& s); 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 // assuming the socket_type s is an ssl socket, make sure it
// verifies the hostname in its SSL handshake // verifies the hostname in its SSL handshake
void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec); void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec);

View File

@ -354,6 +354,10 @@ namespace libtorrent
if (has_peer_choked()) p.flags |= peer_info::remote_choked; if (has_peer_choked()) p.flags |= peer_info::remote_choked;
if (support_extensions()) p.flags |= peer_info::supports_extensions; if (support_extensions()) p.flags |= peer_info::supports_extensions;
if (is_outgoing()) p.flags |= peer_info::local_connection; 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 #ifndef TORRENT_DISABLE_ENCRYPTION
if (m_encrypted) if (m_encrypted)

View File

@ -64,7 +64,8 @@ namespace libtorrent
"invalid key", "invalid key",
"invalid id", "invalid id",
"timeout", "timeout",
"key not found" "key not found",
"duplicated id"
}; };
if (ev < 0 || ev >= i2p_error::num_errors) return "unknown error"; if (ev < 0 || ev >= i2p_error::num_errors) return "unknown error";
@ -74,7 +75,8 @@ namespace libtorrent
i2p_connection::i2p_connection(io_service& ios) i2p_connection::i2p_connection(io_service& ios)
: m_state(sam_idle) : m_state(sam_idle)
, m_io_service(ios) , m_io_service(ios)
{} {
}
i2p_connection::~i2p_connection() i2p_connection::~i2p_connection()
{} {}
@ -89,7 +91,8 @@ namespace libtorrent
// we already seem to have a session to this SAM router // we already seem to have a session to this SAM router
if (m_sam_router.hostname == s.hostname if (m_sam_router.hostname == s.hostname
&& m_sam_router.port == s.port && 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 = s;
m_sam_router.type = proxy_settings::i2p_proxy; m_sam_router.type = proxy_settings::i2p_proxy;
@ -112,10 +115,10 @@ namespace libtorrent
add_outstanding_async("i2p_stream::on_sam_connect"); add_outstanding_async("i2p_stream::on_sam_connect");
#endif #endif
m_sam_socket->async_connect(tcp::endpoint() 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<i2p_stream>)
{ {
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
complete_async("i2p_stream::on_sam_connect"); complete_async("i2p_stream::on_sam_connect");
@ -139,6 +142,7 @@ namespace libtorrent
void i2p_connection::async_name_lookup(char const* name void i2p_connection::async_name_lookup(char const* name
, i2p_connection::name_lookup_handler handler) , i2p_connection::name_lookup_handler handler)
{ {
// TORRENT_ASSERT(is_open());
if (m_state == sam_idle && m_name_lookup.empty()) if (m_state == sam_idle && m_name_lookup.empty())
do_name_lookup(name, handler); do_name_lookup(name, handler);
else else
@ -152,12 +156,12 @@ namespace libtorrent
m_state = sam_name_lookup; m_state = sam_name_lookup;
m_sam_socket->set_name_lookup(name.c_str()); m_sam_socket->set_name_lookup(name.c_str());
boost::shared_ptr<i2p_stream::handler_type> h(new i2p_stream::handler_type( boost::shared_ptr<i2p_stream::handler_type> 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); m_sam_socket->send_name_lookup(h);
} }
void i2p_connection::on_name_lookup(error_code const& ec void i2p_connection::on_name_lookup(error_code const& ec
, name_lookup_handler handler) , name_lookup_handler handler, boost::shared_ptr<i2p_stream>)
{ {
m_state = sam_idle; m_state = sam_idle;
@ -178,20 +182,39 @@ namespace libtorrent
handler(ec, name.c_str()); 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 // TODO: move this to proxy_base and use it in all proxies
bool i2p_stream::handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h) bool i2p_stream::handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
if (!e) return false; if (!e) return false;
// fprintf(stderr, "i2p error \"%s\"\n", e.message().c_str()); // fprintf(stderr, "i2p error \"%s\"\n", e.message().c_str());
(*h)(e); (*h)(e);
error_code ec;
close(ec);
return true; return true;
} }
void i2p_stream::do_connect(error_code const& e, tcp::resolver::iterator i void i2p_stream::do_connect(error_code const& e, tcp::resolver::iterator i
, boost::shared_ptr<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
if (e || i == tcp::resolver::iterator()) if (e || i == tcp::resolver::iterator())
{ {
(*h)(e); (*h)(e);
@ -209,6 +232,7 @@ namespace libtorrent
void i2p_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h) void i2p_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
complete_async("i2p_stream::connected"); complete_async("i2p_stream::connected");
#endif #endif
@ -223,11 +247,12 @@ namespace libtorrent
#endif #endif
async_write(m_sock, asio::buffer(cmd, sizeof(cmd) - 1) async_write(m_sock, asio::buffer(cmd, sizeof(cmd) - 1)
, boost::bind(&i2p_stream::start_read_line, this, _1, h)); , 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<handler_type> h) void i2p_stream::start_read_line(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
complete_async("i2p_stream::start_read_line"); complete_async("i2p_stream::start_read_line");
#endif #endif
@ -244,7 +269,17 @@ namespace libtorrent
char* string_tokenize(char* last, char sep, char** next) char* string_tokenize(char* last, char sep, char** next)
{ {
if (last == 0) return 0; 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; if (*next == 0) return last;
**next = 0; **next = 0;
++(*next); ++(*next);
@ -254,6 +289,7 @@ namespace libtorrent
void i2p_stream::read_line(error_code const& e, boost::shared_ptr<handler_type> h) void i2p_stream::read_line(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
complete_async("i2p_stream::read_line"); complete_async("i2p_stream::read_line");
#endif #endif
@ -261,7 +297,6 @@ namespace libtorrent
int read_pos = m_buffer.size(); int read_pos = m_buffer.size();
// fprintf(stderr, "%c", m_buffer[read_pos - 1]);
// look for \n which means end of the response // look for \n which means end of the response
if (m_buffer[read_pos - 1] != '\n') if (m_buffer[read_pos - 1] != '\n')
{ {
@ -318,6 +353,7 @@ namespace libtorrent
break; break;
} }
// fprintf(stderr, "<<< %s\n", &m_buffer[0]);
ptr = string_tokenize(next, ' ', &next); ptr = string_tokenize(next, ' ', &next);
if (ptr == 0 || expect1 == 0 || strcmp(expect1, ptr)) { handle_error(invalid_response, h); return; } if (ptr == 0 || expect1 == 0 || strcmp(expect1, ptr)) { handle_error(invalid_response, h); return; }
ptr = string_tokenize(next, ' ', &next); ptr = string_tokenize(next, ' ', &next);
@ -331,8 +367,10 @@ namespace libtorrent
{ {
char* name = string_tokenize(next, '=', &next); char* name = string_tokenize(next, '=', &next);
if (name == 0) break; if (name == 0) break;
// fprintf(stderr, "name=\"%s\"\n", name);
char* ptr = string_tokenize(next, ' ', &next); char* ptr = string_tokenize(next, ' ', &next);
if (ptr == 0) { handle_error(invalid_response, h); return; } if (ptr == 0) { handle_error(invalid_response, h); return; }
// fprintf(stderr, "value=\"%s\"\n", ptr);
if (strcmp("RESULT", name) == 0) if (strcmp("RESULT", name) == 0)
{ {
@ -350,6 +388,8 @@ namespace libtorrent
result = i2p_error::timeout; result = i2p_error::timeout;
else if (strcmp("KEY_NOT_FOUND", ptr) == 0) else if (strcmp("KEY_NOT_FOUND", ptr) == 0)
result = i2p_error::key_not_found; result = i2p_error::key_not_found;
else if (strcmp("DUPLICATED_ID", ptr) == 0)
result = i2p_error::duplicated_id;
else else
result = i2p_error::num_errors; // unknown error result = i2p_error::num_errors; // unknown error
} }
@ -423,11 +463,12 @@ namespace libtorrent
void i2p_stream::send_connect(boost::shared_ptr<handler_type> h) void i2p_stream::send_connect(boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
m_state = read_connect_response; m_state = read_connect_response;
char cmd[1024]; char cmd[1024];
int size = snprintf(cmd, sizeof(cmd), "STREAM CONNECT ID=%s DESTINATION=%s\n" int size = snprintf(cmd, sizeof(cmd), "STREAM CONNECT ID=%s DESTINATION=%s\n"
, m_id, m_dest.c_str()); , m_id, m_dest.c_str());
// fputs(cmd, stderr); // fprintf(stderr, ">>> %s", cmd);
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("i2p_stream::start_read_line"); add_outstanding_async("i2p_stream::start_read_line");
#endif #endif
@ -437,10 +478,11 @@ namespace libtorrent
void i2p_stream::send_accept(boost::shared_ptr<handler_type> h) void i2p_stream::send_accept(boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
m_state = read_accept_response; m_state = read_accept_response;
char cmd[400]; char cmd[400];
int size = snprintf(cmd, sizeof(cmd), "STREAM ACCEPT ID=%s\n", m_id); 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 #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("i2p_stream::start_read_line"); add_outstanding_async("i2p_stream::start_read_line");
#endif #endif
@ -450,11 +492,12 @@ namespace libtorrent
void i2p_stream::send_session_create(boost::shared_ptr<handler_type> h) void i2p_stream::send_session_create(boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
m_state = read_session_create_response; m_state = read_session_create_response;
char cmd[400]; char cmd[400];
int size = snprintf(cmd, sizeof(cmd), "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT\n" int size = snprintf(cmd, sizeof(cmd), "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT\n"
, m_id); , m_id);
// fputs(cmd, stderr); // fprintf(stderr, ">>> %s", cmd);
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("i2p_stream::start_read_line"); add_outstanding_async("i2p_stream::start_read_line");
#endif #endif
@ -464,10 +507,11 @@ namespace libtorrent
void i2p_stream::send_name_lookup(boost::shared_ptr<handler_type> h) void i2p_stream::send_name_lookup(boost::shared_ptr<handler_type> h)
{ {
TORRENT_ASSERT(m_magic == 0x1337);
m_state = read_name_lookup_response; m_state = read_name_lookup_response;
char cmd[1024]; char cmd[1024];
int size = snprintf(cmd, sizeof(cmd), "NAMING LOOKUP NAME=%s\n", m_name_lookup.c_str()); 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 #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("i2p_stream::start_read_line"); add_outstanding_async("i2p_stream::start_read_line");
#endif #endif

View File

@ -475,7 +475,6 @@ namespace libtorrent
disconnect(ec); disconnect(ec);
return; return;
} }
TORRENT_ASSERT(m_remote.address() != address_v4::any());
if (m_remote.address().is_v4()) if (m_remote.address().is_v4())
{ {
m_socket->set_option(type_of_service(m_ses.settings().peer_tos), ec); m_socket->set_option(type_of_service(m_ses.settings().peer_tos), ec);

View File

@ -1190,8 +1190,11 @@ namespace libtorrent
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
else else
{ {
std::pair<iterator, iterator> range = find_peers(p->address()); if (!p->is_i2p_addr)
TORRENT_ASSERT(range.second - range.first == 1); {
std::pair<iterator, iterator> range = find_peers(p->address());
TORRENT_ASSERT(range.second - range.first == 1);
}
} }
#endif #endif

View File

@ -2618,8 +2618,41 @@ retry:
} }
#if TORRENT_USE_I2P #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) 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(); open_new_incoming_i2p_connection();
} }
@ -2889,8 +2922,6 @@ retry:
return; return;
} }
TORRENT_ASSERT(endp.address() != address_v4::any());
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
session_log(" <== INCOMING CONNECTION %s type: %s" session_log(" <== INCOMING CONNECTION %s type: %s"
, print_endpoint(endp).c_str(), s->type_name()); , print_endpoint(endp).c_str(), s->type_name());

View File

@ -72,6 +72,17 @@ namespace libtorrent
; ;
} }
#if TORRENT_USE_I2P
bool is_i2p(socket_type const& s)
{
return s.get<i2p_stream>()
#ifdef TORRENT_USE_OPENSSL
|| s.get<ssl_stream<i2p_stream> >()
#endif
;
}
#endif
void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec) void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec)
{ {
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 #if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700