added I2P support
This commit is contained in:
parent
481f19c733
commit
45fd696bc6
|
@ -18,6 +18,7 @@ set(sources
|
|||
http_connection
|
||||
http_stream
|
||||
http_parser
|
||||
i2p_stream
|
||||
identify_client
|
||||
ip_filter
|
||||
peer_connection
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
* added support for i2p torrents
|
||||
|
||||
0.15 release
|
||||
|
||||
* reduced the number of floating point operations (to better support
|
||||
|
|
1
Jamfile
1
Jamfile
|
@ -358,6 +358,7 @@ SOURCES =
|
|||
bt_peer_connection
|
||||
web_peer_connection
|
||||
http_seed_connection
|
||||
i2p_stream
|
||||
instantiate_connection
|
||||
natpmp
|
||||
piece_picker
|
||||
|
|
|
@ -1042,6 +1042,21 @@ These functions returns references to their respective current settings.
|
|||
The ``dht_proxy`` is not available when DHT is disabled.
|
||||
|
||||
|
||||
set_i2p_proxy() i2p_proxy()
|
||||
---------------------------
|
||||
|
||||
::
|
||||
|
||||
void set_i2p_proxy(proxy_settings const&);
|
||||
proxy_settings const& i2p_proxy();
|
||||
|
||||
``set_i2p_proxy`` sets the i2p_ proxy, and tries to open a persistant
|
||||
connection to it. The only used fields in the proxy settings structs
|
||||
are ``hostname`` and ``port``.
|
||||
|
||||
``i2p_proxy`` returns the current i2p proxy in use.
|
||||
|
||||
|
||||
start_dht() stop_dht() set_dht_settings() dht_state()
|
||||
-----------------------------------------------------
|
||||
|
||||
|
|
|
@ -747,6 +747,9 @@ int main(int argc, char* argv[])
|
|||
" -t <seconds> sets the scan interval of the monitor dir\n"
|
||||
" -x <file> loads an emule IP-filter file\n"
|
||||
" -c <limit> sets the max number of connections\n"
|
||||
#if TORRENT_USE_I2P
|
||||
" -i <i2p-host> the hostname to an I2P SAM bridge to use\n"
|
||||
#endif
|
||||
" -C <limit> sets the max cache size. Specified in 16kB blocks\n"
|
||||
" -F <seconds> sets the UI refresh rate. This is the number of\n"
|
||||
" seconds between screen refreshes.\n"
|
||||
|
@ -759,7 +762,6 @@ int main(int argc, char* argv[])
|
|||
|
||||
using namespace libtorrent;
|
||||
session_settings settings;
|
||||
proxy_settings ps;
|
||||
|
||||
settings.user_agent = "client_test/" LIBTORRENT_VERSION;
|
||||
settings.auto_upload_slots_rate_based = true;
|
||||
|
@ -780,7 +782,8 @@ int main(int argc, char* argv[])
|
|||
// monitor when they're not in the directory anymore.
|
||||
handles_t handles;
|
||||
session ses(fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0)
|
||||
, session::start_default_features | session::add_default_plugins, alert::all_categories);
|
||||
, session::add_default_plugins
|
||||
, alert::all_categories & (~alert::dht_notification));
|
||||
|
||||
std::vector<char> in;
|
||||
if (load_file(".ses_state", in) == 0)
|
||||
|
@ -950,6 +953,17 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
break;
|
||||
case 'c': ses.set_max_connections(atoi(arg)); break;
|
||||
#if TORRENT_USE_I2P
|
||||
case 'i':
|
||||
{
|
||||
proxy_settings ps;
|
||||
ps.hostname = arg;
|
||||
ps.port = 7656; // default SAM port
|
||||
ps.type = proxy_settings::i2p_proxy;
|
||||
ses.set_i2p_proxy(ps);
|
||||
break;
|
||||
}
|
||||
#endif // TORRENT_USE_I2P
|
||||
case 'C': settings.cache_size = atoi(arg); break;
|
||||
}
|
||||
++i; // skip the argument
|
||||
|
|
|
@ -33,6 +33,7 @@ libtorrent/http_connection.hpp \
|
|||
libtorrent/http_stream.hpp \
|
||||
libtorrent/http_parser.hpp \
|
||||
libtorrent/http_tracker_connection.hpp \
|
||||
libtorrent/i2p_stream.hpp \
|
||||
libtorrent/identify_client.hpp \
|
||||
libtorrent/instantiate_connection.hpp \
|
||||
libtorrent/intrusive_ptr_base.hpp \
|
||||
|
|
|
@ -294,6 +294,20 @@ namespace libtorrent
|
|||
{ return m_dht_proxy; }
|
||||
#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 on_i2p_open(error_code const& ec);
|
||||
proxy_settings const& i2p_proxy() const
|
||||
{ return m_i2p_conn.proxy(); }
|
||||
void open_new_incoming_i2p_connection();
|
||||
void on_i2p_accept(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e);
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
std::string as_name_for_ip(address const& a);
|
||||
int as_for_ip(address const& a);
|
||||
|
@ -380,15 +394,22 @@ namespace libtorrent
|
|||
};
|
||||
boost::object_pool<
|
||||
policy::ipv4_peer, logging_allocator> m_ipv4_peer_pool;
|
||||
# if TORRENT_USE_IPV6
|
||||
#if TORRENT_USE_IPV6
|
||||
boost::object_pool<
|
||||
policy::ipv6_peer, logging_allocator> m_ipv6_peer_pool;
|
||||
# endif
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
boost::object_pool<
|
||||
policy::i2p_peer, logging_allocator> m_i2p_peer_pool;
|
||||
#endif
|
||||
#else
|
||||
boost::object_pool<policy::ipv4_peer> m_ipv4_peer_pool;
|
||||
# if TORRENT_USE_IPV6
|
||||
#if TORRENT_USE_IPV6
|
||||
boost::object_pool<policy::ipv6_peer> m_ipv6_peer_pool;
|
||||
# endif
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
boost::object_pool<policy::i2p_peer> m_i2p_peer_pool;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// this vector is used to store the block_info
|
||||
|
@ -523,6 +544,11 @@ namespace libtorrent
|
|||
|
||||
void open_new_incoming_socks_connection();
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
i2p_connection m_i2p_conn;
|
||||
boost::shared_ptr<socket_type> m_i2p_listen_socket;
|
||||
#endif
|
||||
|
||||
listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false);
|
||||
|
||||
// the settings for the client
|
||||
|
|
|
@ -115,6 +115,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_USE_WRITEV 1
|
||||
#define TORRENT_USE_IOSTREAM 1
|
||||
|
||||
#define TORRENT_USE_I2P 1
|
||||
|
||||
// should wpath or path be used?
|
||||
#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY \
|
||||
&& BOOST_VERSION >= 103400 && !defined __APPLE__
|
||||
|
|
|
@ -189,6 +189,8 @@ namespace libtorrent
|
|||
reserved6,
|
||||
reserved7,
|
||||
reserved8,
|
||||
|
||||
no_i2p_router,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace libtorrent
|
|||
|
||||
// encodes a string using the base64 scheme
|
||||
TORRENT_EXPORT std::string base64encode(std::string const& s);
|
||||
TORRENT_EXPORT std::string base64decode(std::string const& s);
|
||||
// encodes a string using the base32 scheme
|
||||
TORRENT_EXPORT std::string base32encode(std::string const& s);
|
||||
TORRENT_EXPORT std::string base32decode(std::string const& s);
|
||||
|
|
|
@ -54,6 +54,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/variant_stream.hpp"
|
||||
#endif
|
||||
|
||||
#include "libtorrent/i2p_stream.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
|
@ -108,12 +110,20 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
|
|||
|
||||
void get(std::string const& url, time_duration timeout = seconds(30)
|
||||
, int prio = 0, proxy_settings const* ps = 0, int handle_redirects = 5
|
||||
, std::string const& user_agent = "", address const& bind_addr = address_v4::any());
|
||||
, std::string const& user_agent = "", address const& bind_addr = address_v4::any()
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn = 0
|
||||
#endif
|
||||
);
|
||||
|
||||
void start(std::string const& hostname, std::string const& port
|
||||
, time_duration timeout, int prio = 0, proxy_settings const* ps = 0
|
||||
, bool ssl = false, int handle_redirect = 5
|
||||
, address const& bind_addr = address_v4::any());
|
||||
, address const& bind_addr = address_v4::any()
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn = 0
|
||||
#endif
|
||||
);
|
||||
|
||||
void close();
|
||||
|
||||
|
@ -127,6 +137,10 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
|
|||
|
||||
private:
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void on_i2p_resolve(error_code const& e
|
||||
, char const* destination);
|
||||
#endif
|
||||
void on_resolve(error_code const& e
|
||||
, tcp::resolver::iterator i);
|
||||
void queue_connect();
|
||||
|
@ -146,6 +160,9 @@ private:
|
|||
variant_stream<socket_type, ssl_stream<socket_type> > m_sock;
|
||||
#else
|
||||
socket_type m_sock;
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
i2p_connection* m_i2p_conn;
|
||||
#endif
|
||||
int m_read_pos;
|
||||
tcp::resolver m_resolver;
|
||||
|
|
|
@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/tracker_manager.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/i2p_stream.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -73,7 +74,11 @@ namespace libtorrent
|
|||
, boost::weak_ptr<request_callback> c
|
||||
, aux::session_impl const& ses
|
||||
, proxy_settings const& ps
|
||||
, std::string const& password = "");
|
||||
, std::string const& password = ""
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn = 0
|
||||
#endif
|
||||
);
|
||||
|
||||
void start();
|
||||
void close();
|
||||
|
@ -100,6 +105,9 @@ namespace libtorrent
|
|||
proxy_settings const& m_ps;
|
||||
connection_queue& m_cc;
|
||||
io_service& m_ios;
|
||||
#if TORRENT_USE_I2P
|
||||
i2p_connection* m_i2p_conn;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2009, 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_I2P_STREAM_HPP_INCLUDED
|
||||
#define TORRENT_I2P_STREAM_HPP_INCLUDED
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
|
||||
#include "libtorrent/proxy_base.hpp"
|
||||
#include "libtorrent/session_settings.hpp"
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
namespace i2p_error {
|
||||
|
||||
enum i2p_error_code
|
||||
{
|
||||
no_error = 0,
|
||||
parse_failed,
|
||||
cant_reach_peer,
|
||||
i2p_error,
|
||||
invalid_key,
|
||||
invalid_id,
|
||||
timeout,
|
||||
key_not_found,
|
||||
num_errors
|
||||
};
|
||||
}
|
||||
|
||||
struct TORRENT_EXPORT i2p_error_category : boost::system::error_category
|
||||
{
|
||||
virtual const char* name() const;
|
||||
virtual std::string message(int ev) const;
|
||||
virtual boost::system::error_condition default_error_condition(int ev) const
|
||||
{ return boost::system::error_condition(ev, *this); }
|
||||
};
|
||||
|
||||
extern i2p_error_category i2p_category;
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
enum command_t
|
||||
{
|
||||
cmd_none,
|
||||
cmd_create_session,
|
||||
cmd_connect,
|
||||
cmd_accept,
|
||||
cmd_name_lookup,
|
||||
cmd_incoming
|
||||
};
|
||||
|
||||
void set_command(command_t c) { m_command = c; }
|
||||
|
||||
void set_session_id(char const* id) { m_id = id; }
|
||||
|
||||
void set_destination(std::string const& d) { m_dest = d; }
|
||||
std::string const& destination() { return m_dest; }
|
||||
|
||||
typedef boost::function<void(error_code const&)> handler_type;
|
||||
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
{
|
||||
// since we don't support regular endpoints, just ignore the one
|
||||
// provided and use m_dest.
|
||||
|
||||
// the connect is split up in the following steps:
|
||||
// 1. resolve name of proxy server
|
||||
// 2. connect to SAM bridge
|
||||
// 4 send command message (CONNECT/ACCEPT)
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
|
||||
tcp::resolver::query q(m_hostname
|
||||
, boost::lexical_cast<std::string>(m_port));
|
||||
m_resolver.async_resolve(q, boost::bind(
|
||||
&i2p_stream::do_connect, this, _1, _2, h));
|
||||
}
|
||||
|
||||
std::string name_lookup() const { return m_name_lookup; }
|
||||
void set_name_lookup(char const* name) { m_name_lookup = name; }
|
||||
|
||||
void send_name_lookup(boost::shared_ptr<handler_type> h);
|
||||
|
||||
private:
|
||||
|
||||
bool handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h);
|
||||
void do_connect(error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h);
|
||||
void connected(error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void start_read_line(error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void read_line(error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void send_connect(boost::shared_ptr<handler_type> h);
|
||||
void send_accept(boost::shared_ptr<handler_type> h);
|
||||
void send_session_create(boost::shared_ptr<handler_type> h);
|
||||
|
||||
// send and receive buffer
|
||||
std::vector<char> m_buffer;
|
||||
char const* m_id;
|
||||
int m_command; // 0 = connect, 1 = accept
|
||||
std::string m_dest;
|
||||
std::string m_name_lookup;
|
||||
|
||||
enum state_t
|
||||
{
|
||||
read_hello_response,
|
||||
read_connect_response,
|
||||
read_accept_response,
|
||||
read_session_create_response,
|
||||
read_name_lookup_response,
|
||||
};
|
||||
|
||||
int m_state;
|
||||
};
|
||||
|
||||
class i2p_connection
|
||||
{
|
||||
public:
|
||||
i2p_connection(io_service& ios);
|
||||
~i2p_connection();
|
||||
|
||||
proxy_settings const& proxy() const { return m_sam_router; }
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return m_sam_socket
|
||||
&& m_sam_socket->is_open()
|
||||
&& m_state != sam_connecting;
|
||||
}
|
||||
void open(proxy_settings const& s, i2p_stream::handler_type const& h);
|
||||
void close();
|
||||
|
||||
char const* session_id() const { return m_session_id.c_str(); }
|
||||
std::string const& local_endpoint() const { return m_i2p_local_endpoint; }
|
||||
|
||||
typedef boost::function<void(error_code const&, char const*)> name_lookup_handler;
|
||||
void async_name_lookup(char const* name, name_lookup_handler handler);
|
||||
|
||||
private:
|
||||
|
||||
void on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h);
|
||||
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);
|
||||
|
||||
void set_local_endpoint(error_code const& ec, char const* dest);
|
||||
|
||||
// to talk to i2p SAM bridge
|
||||
boost::shared_ptr<i2p_stream> m_sam_socket;
|
||||
proxy_settings m_sam_router;
|
||||
|
||||
// our i2p endpoint key
|
||||
std::string m_i2p_local_endpoint;
|
||||
std::string m_session_id;
|
||||
|
||||
std::list<std::pair<std::string, name_lookup_handler> > m_name_lookup;
|
||||
|
||||
enum state_t
|
||||
{
|
||||
sam_connecting,
|
||||
sam_name_lookup,
|
||||
sam_idle
|
||||
};
|
||||
|
||||
state_t m_state;
|
||||
|
||||
io_service& m_io_service;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // TORRENT_USE_I2P
|
||||
|
||||
#endif
|
||||
|
|
@ -73,6 +73,11 @@ namespace libtorrent
|
|||
void pulse();
|
||||
|
||||
struct peer;
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
policy::peer* add_i2p_peer(char const* destination, int source, char flags);
|
||||
#endif
|
||||
|
||||
// this is called once for every peer we get from
|
||||
// the tracker, pex, lsd or dht.
|
||||
policy::peer* add_peer(const tcp::endpoint& remote, const peer_id& pid
|
||||
|
@ -129,6 +134,7 @@ namespace libtorrent
|
|||
size_type total_upload() const;
|
||||
|
||||
libtorrent::address address() const;
|
||||
char const* dest() const;
|
||||
|
||||
tcp::endpoint ip() const { return tcp::endpoint(address(), port); }
|
||||
|
||||
|
@ -172,7 +178,6 @@ namespace libtorrent
|
|||
// in number of seconds since session was created
|
||||
boost::uint16_t last_connected;
|
||||
|
||||
|
||||
// the port this peer is or was connected on
|
||||
boost::uint16_t port;
|
||||
|
||||
|
@ -233,6 +238,10 @@ namespace libtorrent
|
|||
// the one to use, false if it's the v4 one
|
||||
bool is_v6_addr:1;
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
// set if the i2p_destination is in use in the addr union
|
||||
bool is_i2p_addr:1;
|
||||
#endif
|
||||
|
||||
// if this is true, the peer has previously
|
||||
// participated in a piece that failed the piece
|
||||
|
@ -261,6 +270,17 @@ namespace libtorrent
|
|||
address_v4 addr;
|
||||
};
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
struct i2p_peer : peer
|
||||
{
|
||||
i2p_peer(char const* destination, bool connectable, int src);
|
||||
i2p_peer(char const* destination);
|
||||
~i2p_peer();
|
||||
|
||||
char* destination;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_IPV6
|
||||
struct ipv6_peer : peer
|
||||
{
|
||||
|
@ -287,9 +307,27 @@ namespace libtorrent
|
|||
return lhs < rhs->address();
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
bool operator()(
|
||||
peer const* lhs, char const* rhs) const
|
||||
{
|
||||
return strcmp(lhs->dest(), rhs) < 0;
|
||||
}
|
||||
|
||||
bool operator()(
|
||||
char const* lhs, peer const* rhs) const
|
||||
{
|
||||
return strcmp(lhs, rhs->dest()) < 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator()(
|
||||
peer const* lhs, peer const* rhs) const
|
||||
{
|
||||
#if TORRENT_USE_I2P
|
||||
if (rhs->is_i2p_addr == lhs->is_i2p_addr)
|
||||
return strcmp(lhs->dest(), rhs->dest()) < 0;
|
||||
#endif
|
||||
return lhs->address() < rhs->address();
|
||||
}
|
||||
};
|
||||
|
@ -328,6 +366,10 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
|
||||
void update_peer(policy::peer* p, int src, int flags
|
||||
, tcp::endpoint const& remote, char const* destination);
|
||||
bool insert_peer(policy::peer* p, iterator iter, int flags);
|
||||
|
||||
bool compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const;
|
||||
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||
, address const& external_ip) const;
|
||||
|
@ -376,15 +418,48 @@ namespace libtorrent
|
|||
: peer(ip.port(), connectable, src)
|
||||
, addr(ip.address().to_v4())
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
is_v6_addr = false;
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
is_i2p_addr = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline policy::ipv4_peer::ipv4_peer(libtorrent::address const& a)
|
||||
: addr(a.to_v4())
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
is_v6_addr = false;
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
is_i2p_addr = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
inline policy::i2p_peer::i2p_peer(char const* dest, bool connectable, int src)
|
||||
: peer(0, connectable, src), destination(strdup(dest))
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
is_v6_addr = false;
|
||||
#endif
|
||||
is_i2p_addr = true;
|
||||
}
|
||||
inline policy::i2p_peer::i2p_peer(char const* dest)
|
||||
: destination(strdup(dest))
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
is_v6_addr = false;
|
||||
#endif
|
||||
is_i2p_addr = true;
|
||||
}
|
||||
|
||||
inline policy::i2p_peer::~i2p_peer()
|
||||
{ free(destination); }
|
||||
#endif // TORRENT_USE_I2P
|
||||
|
||||
#if TORRENT_USE_IPV6
|
||||
inline policy::ipv6_peer::ipv6_peer(
|
||||
tcp::endpoint const& ip, bool connectable, int src
|
||||
)
|
||||
|
@ -392,20 +467,41 @@ namespace libtorrent
|
|||
, addr(ip.address().to_v6().to_bytes())
|
||||
{
|
||||
is_v6_addr = true;
|
||||
#if TORRENT_USE_I2P
|
||||
is_i2p_addr = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline policy::ipv6_peer::ipv6_peer(libtorrent::address const& a)
|
||||
: addr(a.to_v6().to_bytes())
|
||||
{
|
||||
is_v6_addr = true;
|
||||
#if TORRENT_USE_I2P
|
||||
is_i2p_addr = false;
|
||||
#endif
|
||||
}
|
||||
#endif // TORRENT_USE_IPV6
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
inline char const* policy::peer::dest() const
|
||||
{
|
||||
if (is_i2p_addr)
|
||||
return static_cast<policy::i2p_peer const*>(this)->destination;
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
inline libtorrent::address policy::peer::address() const
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
if (is_v6_addr)
|
||||
return libtorrent::address_v6(
|
||||
static_cast<policy::ipv6_peer const*>(this)->addr);
|
||||
else
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p_addr) return libtorrent::address();
|
||||
else
|
||||
#endif
|
||||
return static_cast<policy::ipv4_peer const*>(this)->addr;
|
||||
}
|
||||
|
|
|
@ -375,6 +375,11 @@ namespace libtorrent
|
|||
proxy_settings const& dht_proxy() const;
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void set_i2p_proxy(proxy_settings const& s);
|
||||
proxy_settings const& i2p_proxy() const;
|
||||
#endif
|
||||
|
||||
int upload_rate_limit() const;
|
||||
int download_rate_limit() const;
|
||||
int local_upload_rate_limit() const;
|
||||
|
|
|
@ -71,7 +71,9 @@ namespace libtorrent
|
|||
http,
|
||||
// http proxy with basic authentication
|
||||
// uses username and password
|
||||
http_pw
|
||||
http_pw,
|
||||
// route through a i2p SAM proxy
|
||||
i2p_proxy
|
||||
};
|
||||
|
||||
proxy_type type;
|
||||
|
@ -176,6 +178,7 @@ namespace libtorrent
|
|||
, write_cache_line_size(32)
|
||||
, optimistic_disk_retry(10 * 60)
|
||||
, disable_hash_checks(false)
|
||||
, allow_i2p_mixed(false)
|
||||
{}
|
||||
|
||||
// this is the user agent that will be sent to the tracker
|
||||
|
@ -621,6 +624,15 @@ namespace libtorrent
|
|||
// testing purposes (typically combined with
|
||||
// disabled_storage)
|
||||
bool disable_hash_checks;
|
||||
|
||||
// if this is true, i2p torrents are allowed
|
||||
// to also get peers from other sources than
|
||||
// the tracker, and connect to regular IPs,
|
||||
// not providing any anonymization. This may
|
||||
// be useful if the user is not interested in
|
||||
// the anonymization of i2p, but still wants to
|
||||
// be able to connect to i2p peers.
|
||||
bool allow_i2p_mixed;
|
||||
};
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
|
|
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/socks5_stream.hpp"
|
||||
#include "libtorrent/http_stream.hpp"
|
||||
#include "libtorrent/i2p_stream.hpp"
|
||||
#include "libtorrent/variant_stream.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
|
@ -42,7 +43,11 @@ namespace libtorrent
|
|||
typedef variant_stream<
|
||||
stream_socket
|
||||
, socks5_stream
|
||||
, http_stream> socket_type;
|
||||
, http_stream
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_stream
|
||||
#endif
|
||||
> socket_type;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -105,6 +105,7 @@ namespace libtorrent
|
|||
explicit time_duration(boost::int64_t d) : diff(d) {}
|
||||
time_duration& operator-=(time_duration const& c) { diff -= c.diff; return *this; }
|
||||
time_duration& operator+=(time_duration const& c) { diff += c.diff; return *this; }
|
||||
time_duration& operator*=(int v) { diff *= v; return *this; }
|
||||
time_duration operator+(time_duration const& c) { return time_duration(diff + c.diff); }
|
||||
time_duration operator-(time_duration const& c) { return time_duration(diff - c.diff); }
|
||||
boost::int64_t diff;
|
||||
|
|
|
@ -513,6 +513,10 @@ namespace libtorrent
|
|||
// all seeds and let the tracker know we're finished.
|
||||
void completed();
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void on_i2p_resolve(error_code const& ec, char const* dest);
|
||||
#endif
|
||||
|
||||
// this is the asio callback that is called when a name
|
||||
// lookup for a PEER is completed.
|
||||
void on_peer_name_lookup(error_code const& e, tcp::resolver::iterator i
|
||||
|
|
|
@ -256,6 +256,8 @@ namespace libtorrent
|
|||
|
||||
bool priv() const { return m_private; }
|
||||
|
||||
bool is_i2p() const { return m_i2p; }
|
||||
|
||||
int piece_size(int index) const { return m_files.piece_size(index); }
|
||||
|
||||
sha1_hash hash_for_piece(int index) const
|
||||
|
@ -367,6 +369,12 @@ namespace libtorrent
|
|||
// be announced on the dht
|
||||
bool m_private;
|
||||
|
||||
// this is true if one of the trackers has an .i2p top
|
||||
// domain in its hostname. This means the DHT and LSD
|
||||
// features are disabled for this torrent (unless the
|
||||
// settings allows mixing i2p peers with regular peers)
|
||||
bool m_i2p;
|
||||
|
||||
// this is a copy of the info section from the torrent.
|
||||
// it use maintained in this flat format in order to
|
||||
// make it available through the metadata extension
|
||||
|
|
|
@ -26,7 +26,7 @@ socks5_stream.cpp http_stream.cpp connection_queue.cpp \
|
|||
disk_io_thread.cpp ut_metadata.cpp lt_trackers.cpp magnet_uri.cpp udp_socket.cpp smart_ban.cpp \
|
||||
http_parser.cpp gzip.cpp disk_buffer_holder.cpp create_torrent.cpp GeoIP.c \
|
||||
parse_url.cpp file_storage.cpp error_code.cpp ConvertUTF.cpp \
|
||||
allocator.cpp \
|
||||
allocator.cpp i2p_stream.cpp \
|
||||
$(kademlia_sources)
|
||||
|
||||
noinst_HEADERS = \
|
||||
|
@ -67,6 +67,7 @@ $(top_srcdir)/include/libtorrent/http_stream.hpp \
|
|||
$(top_srcdir)/include/libtorrent/http_parser.hpp \
|
||||
$(top_srcdir)/include/libtorrent/session_settings.hpp \
|
||||
$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/i2p_stream.hpp \
|
||||
$(top_srcdir)/include/libtorrent/identify_client.hpp \
|
||||
$(top_srcdir)/include/libtorrent/instantiate_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/intrusive_ptr_base.hpp \
|
||||
|
|
|
@ -184,6 +184,7 @@ namespace libtorrent
|
|||
"",
|
||||
"",
|
||||
"",
|
||||
"no i2p router is set up",
|
||||
};
|
||||
if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0]))
|
||||
return "Unknown error";
|
||||
|
|
|
@ -51,7 +51,11 @@ enum { max_bottled_buffer = 1024 * 1024 };
|
|||
|
||||
void http_connection::get(std::string const& url, time_duration timeout, int prio
|
||||
, proxy_settings const* ps, int handle_redirects, std::string const& user_agent
|
||||
, address const& bind_addr)
|
||||
, address const& bind_addr
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn
|
||||
#endif
|
||||
)
|
||||
{
|
||||
std::string protocol;
|
||||
std::string auth;
|
||||
|
@ -137,12 +141,20 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri
|
|||
sendbuffer.assign(request);
|
||||
m_url = url;
|
||||
start(hostname, to_string(port).elems, timeout, prio
|
||||
, ps, ssl, handle_redirects, bind_addr);
|
||||
, ps, ssl, handle_redirects, bind_addr
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_conn
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void http_connection::start(std::string const& hostname, std::string const& port
|
||||
, time_duration timeout, int prio, proxy_settings const* ps, bool ssl, int handle_redirects
|
||||
, address const& bind_addr)
|
||||
, address const& bind_addr
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn
|
||||
#endif
|
||||
)
|
||||
{
|
||||
TORRENT_ASSERT(prio >= 0 && prio < 2);
|
||||
|
||||
|
@ -184,20 +196,69 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||
error_code ec;
|
||||
m_sock.close(ec);
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
bool is_i2p = false;
|
||||
char const* top_domain = strrchr(hostname.c_str(), '.');
|
||||
if (top_domain && strcmp(top_domain, ".i2p") == 0 && i2p_conn)
|
||||
{
|
||||
// this is an i2p name, we need to use the sam connection
|
||||
// to do the name lookup
|
||||
is_i2p = true;
|
||||
m_i2p_conn = i2p_conn;
|
||||
// quadruple the timeout for i2p destinations
|
||||
// because i2p is sloooooow
|
||||
m_timeout *= 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p && i2p_conn->proxy().type != proxy_settings::i2p_proxy)
|
||||
{
|
||||
m_resolver.get_io_service().post(boost::bind(&http_connection::callback
|
||||
, this, error_code(errors::no_i2p_router, libtorrent_category), (char*)0, 0));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
if (m_ssl)
|
||||
{
|
||||
m_sock.instantiate<ssl_stream<socket_type> >(m_resolver.get_io_service());
|
||||
ssl_stream<socket_type>* s = m_sock.get<ssl_stream<socket_type> >();
|
||||
TORRENT_ASSERT(s);
|
||||
bool ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, s->next_layer());
|
||||
bool ret = false;
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p)
|
||||
{
|
||||
ret = instantiate_connection(m_resolver.get_io_service(), i2p_conn->proxy()
|
||||
, s->next_layer());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, s->next_layer());
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sock.instantiate<socket_type>(m_resolver.get_io_service());
|
||||
bool ret = instantiate_connection(m_resolver.get_io_service()
|
||||
, m_proxy, *m_sock.get<socket_type>());
|
||||
bool ret = false;
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p)
|
||||
{
|
||||
ret = instantiate_connection(m_resolver.get_io_service(), i2p_conn->proxy()
|
||||
, *m_sock.get<socket_type>());
|
||||
TORRENT_ASSERT(m_sock.get<socket_type>());
|
||||
TORRENT_ASSERT(m_sock.get<socket_type>()->get<i2p_stream>());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = instantiate_connection(m_resolver.get_io_service()
|
||||
, m_proxy, *m_sock.get<socket_type>());
|
||||
}
|
||||
TORRENT_ASSERT(ret);
|
||||
}
|
||||
#else
|
||||
|
@ -217,9 +278,19 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||
}
|
||||
}
|
||||
|
||||
tcp::resolver::query query(hostname, port);
|
||||
m_resolver.async_resolve(query, bind(&http_connection::on_resolve
|
||||
, shared_from_this(), _1, _2));
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p)
|
||||
{
|
||||
i2p_conn->async_name_lookup(hostname.c_str(), bind(&http_connection::on_i2p_resolve
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
tcp::resolver::query query(hostname, port);
|
||||
m_resolver.async_resolve(query, bind(&http_connection::on_resolve
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
m_hostname = hostname;
|
||||
m_port = port;
|
||||
}
|
||||
|
@ -290,6 +361,34 @@ void http_connection::close()
|
|||
m_abort = true;
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void http_connection::on_i2p_resolve(error_code const& e
|
||||
, char const* destination)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
callback(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
TORRENT_ASSERT(m_ssl == false);
|
||||
TORRENT_ASSERT(m_sock.get<socket_type>());
|
||||
TORRENT_ASSERT(m_sock.get<socket_type>()->get<i2p_stream>());
|
||||
m_sock.get<socket_type>()->get<i2p_stream>()->set_destination(destination);
|
||||
m_sock.get<socket_type>()->get<i2p_stream>()->set_command(i2p_stream::cmd_connect);
|
||||
m_sock.get<socket_type>()->get<i2p_stream>()->set_session_id(m_i2p_conn->session_id());
|
||||
#else
|
||||
m_sock.get<i2p_stream>()->set_destination(destination);
|
||||
m_sock.get<i2p_stream>()->set_command(i2p_stream::cmd_connect);
|
||||
m_sock.get<i2p_stream>()->set_session_id(m_i2p_conn->session_id());
|
||||
#endif
|
||||
m_sock.async_connect(tcp::endpoint(), boost::bind(&http_connection::on_connect
|
||||
, shared_from_this(), _1));
|
||||
}
|
||||
#endif
|
||||
|
||||
void http_connection::on_resolve(error_code const& e
|
||||
, tcp::resolver::iterator i)
|
||||
{
|
||||
|
|
|
@ -73,13 +73,20 @@ namespace libtorrent
|
|||
, boost::weak_ptr<request_callback> c
|
||||
, aux::session_impl const& ses
|
||||
, proxy_settings const& ps
|
||||
, std::string const& auth)
|
||||
, std::string const& auth
|
||||
#if TORRENT_USE_I2P
|
||||
, i2p_connection* i2p_conn
|
||||
#endif
|
||||
)
|
||||
: tracker_connection(man, req, ios, c)
|
||||
, m_man(man)
|
||||
, m_ses(ses)
|
||||
, m_ps(ps)
|
||||
, m_cc(cc)
|
||||
, m_ios(ios)
|
||||
#if TORRENT_USE_I2P
|
||||
, m_i2p_conn(i2p_conn)
|
||||
#endif
|
||||
{}
|
||||
|
||||
void http_tracker_connection::start()
|
||||
|
@ -102,6 +109,14 @@ namespace libtorrent
|
|||
url.replace(pos, 8, "scrape");
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
// defined in torrent_info.cpp
|
||||
bool is_i2p_url(std::string const& url);
|
||||
bool i2p = is_i2p_url(url);
|
||||
#else
|
||||
static const bool i2p = false;
|
||||
#endif
|
||||
|
||||
session_settings const& settings = m_ses.settings();
|
||||
|
||||
// if request-string already contains
|
||||
|
@ -125,7 +140,9 @@ namespace libtorrent
|
|||
"%s"
|
||||
#endif
|
||||
, escape_string((const char*)&tracker_req().pid[0], 20).c_str()
|
||||
, tracker_req().listen_port
|
||||
// the i2p tracker seems to verify that the port is not 0,
|
||||
// even though it ignores it otherwise
|
||||
, i2p ? 1 : tracker_req().listen_port
|
||||
, tracker_req().uploaded
|
||||
, tracker_req().downloaded
|
||||
, tracker_req().left
|
||||
|
@ -145,6 +162,16 @@ namespace libtorrent
|
|||
url += event_string[tracker_req().event - 1];
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
if (i2p)
|
||||
{
|
||||
url += "&ip=";
|
||||
url += escape_string(m_i2p_conn->local_endpoint().c_str()
|
||||
, m_i2p_conn->local_endpoint().size());
|
||||
url += ".i2p";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (settings.announce_ip != address())
|
||||
{
|
||||
error_code ec;
|
||||
|
@ -152,13 +179,13 @@ namespace libtorrent
|
|||
if (!ec) url += "&ip=" + ip;
|
||||
}
|
||||
|
||||
if (!tracker_req().ipv6.empty())
|
||||
if (!tracker_req().ipv6.empty() && !i2p)
|
||||
{
|
||||
url += "&ipv6=";
|
||||
url += tracker_req().ipv6;
|
||||
}
|
||||
|
||||
if (!tracker_req().ipv4.empty())
|
||||
if (!tracker_req().ipv4.empty() && !i2p)
|
||||
{
|
||||
url += "&ipv4=";
|
||||
url += tracker_req().ipv4;
|
||||
|
@ -176,7 +203,11 @@ namespace libtorrent
|
|||
:settings.tracker_completion_timeout;
|
||||
|
||||
m_tracker_connection->get(url, seconds(timeout)
|
||||
, 1, &m_ps, 5, settings.user_agent, bind_interface());
|
||||
, 1, &m_ps, 5, settings.user_agent, bind_interface()
|
||||
#if TORRENT_USE_I2P
|
||||
, m_i2p_conn
|
||||
#endif
|
||||
);
|
||||
|
||||
// the url + 100 estimated header size
|
||||
sent_bytes(url.size() + 100);
|
||||
|
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2009, 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/pch.hpp"
|
||||
|
||||
#include "libtorrent/i2p_stream.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
i2p_error_category i2p_category;
|
||||
|
||||
const char* i2p_error_category::name() const
|
||||
{
|
||||
return "i2p error";
|
||||
}
|
||||
|
||||
std::string i2p_error_category::message(int ev) const
|
||||
{
|
||||
static char const* messages[] =
|
||||
{
|
||||
"no error",
|
||||
"parse failed",
|
||||
"cannot reach peer",
|
||||
"i2p error",
|
||||
"invalid key",
|
||||
"invalid id",
|
||||
"timeout",
|
||||
"key not found"
|
||||
};
|
||||
|
||||
if (ev < 0 || ev > i2p_error::num_errors) return "unknown error";
|
||||
return messages[ev];
|
||||
}
|
||||
|
||||
i2p_connection::i2p_connection(io_service& ios)
|
||||
: m_io_service(ios)
|
||||
{}
|
||||
|
||||
i2p_connection::~i2p_connection()
|
||||
{}
|
||||
|
||||
void i2p_connection::close()
|
||||
{
|
||||
m_sam_socket->close();
|
||||
}
|
||||
|
||||
void i2p_connection::open(proxy_settings const& s, i2p_stream::handler_type const& handler)
|
||||
{
|
||||
// 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_router = s;
|
||||
m_sam_router.type = proxy_settings::i2p_proxy;
|
||||
|
||||
m_state = sam_connecting;
|
||||
|
||||
char tmp[20];
|
||||
std::generate(tmp, tmp + sizeof(tmp), &std::rand);
|
||||
m_session_id.resize(sizeof(tmp)*2);
|
||||
to_hex(tmp, 20, &m_session_id[0]);
|
||||
|
||||
m_sam_socket.reset(new i2p_stream(m_io_service));
|
||||
m_sam_socket->set_proxy(m_sam_router.hostname, m_sam_router.port);
|
||||
m_sam_socket->set_command(i2p_stream::cmd_create_session);
|
||||
m_sam_socket->set_session_id(m_session_id.c_str());
|
||||
|
||||
m_sam_socket->async_connect(tcp::endpoint()
|
||||
, boost::bind(&i2p_connection::on_sam_connect, this, _1, handler));
|
||||
}
|
||||
|
||||
void i2p_connection::on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h)
|
||||
{
|
||||
m_state = sam_idle;
|
||||
|
||||
do_name_lookup("ME", boost::bind(&i2p_connection::set_local_endpoint, this, _1, _2));
|
||||
h(ec);
|
||||
}
|
||||
|
||||
void i2p_connection::set_local_endpoint(error_code const& ec, char const* dest)
|
||||
{
|
||||
if (ec || dest == 0)
|
||||
{
|
||||
m_i2p_local_endpoint.clear();
|
||||
return;
|
||||
}
|
||||
m_i2p_local_endpoint = dest;
|
||||
}
|
||||
|
||||
void i2p_connection::async_name_lookup(char const* name
|
||||
, i2p_connection::name_lookup_handler handler)
|
||||
{
|
||||
if (m_state == sam_idle && m_name_lookup.empty())
|
||||
do_name_lookup(name, handler);
|
||||
else
|
||||
m_name_lookup.push_back(std::make_pair(std::string(name), handler));
|
||||
}
|
||||
|
||||
void i2p_connection::do_name_lookup(std::string const& name
|
||||
, name_lookup_handler const& handler)
|
||||
{
|
||||
TORRENT_ASSERT(m_state == sam_idle);
|
||||
m_state = sam_name_lookup;
|
||||
m_sam_socket->set_name_lookup(name.c_str());
|
||||
boost::shared_ptr<i2p_stream::handler_type> h(new i2p_stream::handler_type(
|
||||
boost::bind(&i2p_connection::on_name_lookup, this, _1, handler)));
|
||||
m_sam_socket->send_name_lookup(h);
|
||||
}
|
||||
|
||||
void i2p_connection::on_name_lookup(error_code const& ec
|
||||
, name_lookup_handler handler)
|
||||
{
|
||||
m_state = sam_idle;
|
||||
|
||||
std::string name = m_sam_socket->name_lookup();
|
||||
if (!m_name_lookup.empty())
|
||||
{
|
||||
std::pair<std::string, name_lookup_handler>& nl = m_name_lookup.front();
|
||||
do_name_lookup(nl.first, nl.second);
|
||||
m_name_lookup.pop_front();
|
||||
}
|
||||
|
||||
if (ec)
|
||||
{
|
||||
handler(ec, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
handler(ec, name.c_str());
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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<handler_type> h)
|
||||
{
|
||||
if (e || i == tcp::resolver::iterator())
|
||||
{
|
||||
(*h)(e);
|
||||
error_code ec;
|
||||
close(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sock.async_connect(i->endpoint(), boost::bind(
|
||||
&i2p_stream::connected, this, _1, h));
|
||||
}
|
||||
|
||||
void i2p_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (handle_error(e, h)) return;
|
||||
|
||||
// send hello command
|
||||
m_state = read_hello_response;
|
||||
static const char cmd[] = "HELLO VERSION MIN=3.0 MAX=3.0\n";
|
||||
async_write(m_sock, asio::buffer(cmd, sizeof(cmd) - 1)
|
||||
, boost::bind(&i2p_stream::start_read_line, this, _1, h));
|
||||
// fputs(cmd, stderr);
|
||||
}
|
||||
|
||||
void i2p_stream::start_read_line(error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (handle_error(e, h)) return;
|
||||
|
||||
m_buffer.resize(1);
|
||||
async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&i2p_stream::read_line, this, _1, h));
|
||||
}
|
||||
|
||||
char* string_tokenize(char* last, char sep, char** next)
|
||||
{
|
||||
if (last == 0) return 0;
|
||||
*next = strchr(last, sep);
|
||||
if (*next == 0) return last;
|
||||
**next = 0;
|
||||
++(*next);
|
||||
while (**next == sep && **next) ++(*next);
|
||||
return last;
|
||||
}
|
||||
|
||||
void i2p_stream::read_line(error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (handle_error(e, h)) return;
|
||||
|
||||
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')
|
||||
{
|
||||
// read another byte from the socket
|
||||
m_buffer.resize(read_pos + 1);
|
||||
async_read(m_sock, asio::buffer(&m_buffer[read_pos], 1)
|
||||
, boost::bind(&i2p_stream::read_line, this, _1, h));
|
||||
return;
|
||||
}
|
||||
m_buffer[read_pos - 1] = 0;
|
||||
|
||||
if (m_command == cmd_incoming)
|
||||
{
|
||||
// this is the line containing the destination
|
||||
// of the incoming connection in an accept call
|
||||
m_dest = &m_buffer[0];
|
||||
(*h)(e);
|
||||
std::vector<char>().swap(m_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
error_code invalid_response(i2p_error::parse_failed
|
||||
, i2p_category);
|
||||
|
||||
// null-terminate the string and parse it
|
||||
m_buffer.push_back(0);
|
||||
char* ptr = &m_buffer[0];
|
||||
char* next = ptr;
|
||||
|
||||
char const* expect1 = 0;
|
||||
char const* expect2 = 0;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case read_hello_response:
|
||||
expect1 = "HELLO";
|
||||
expect2 = "REPLY";
|
||||
break;
|
||||
case read_connect_response:
|
||||
case read_accept_response:
|
||||
expect1 = "STREAM";
|
||||
expect2 = "STATUS";
|
||||
break;
|
||||
case read_session_create_response:
|
||||
expect1 = "SESSION";
|
||||
expect2 = "STATUS";
|
||||
break;
|
||||
case read_name_lookup_response:
|
||||
expect1 = "NAMING";
|
||||
expect2 = "REPLY";
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = string_tokenize(next, ' ', &next);
|
||||
if (ptr == 0 || strcmp(expect1, ptr)) { handle_error(invalid_response, h); return; }
|
||||
ptr = string_tokenize(next, ' ', &next);
|
||||
if (ptr == 0 || strcmp(expect2, ptr)) { handle_error(invalid_response, h); return; }
|
||||
|
||||
int result = 0;
|
||||
char const* message = 0;
|
||||
float version = 3.0f;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char* name = string_tokenize(next, '=', &next);
|
||||
if (name == 0) break;
|
||||
char* ptr = string_tokenize(next, ' ', &next);
|
||||
if (ptr == 0) { handle_error(invalid_response, h); return; }
|
||||
|
||||
if (strcmp("RESULT", name) == 0)
|
||||
{
|
||||
if (strcmp("OK", ptr) == 0)
|
||||
result = i2p_error::no_error;
|
||||
else if (strcmp("CANT_REACH_PEER", ptr) == 0)
|
||||
result = i2p_error::cant_reach_peer;
|
||||
else if (strcmp("I2P_ERROR", ptr) == 0)
|
||||
result = i2p_error::i2p_error;
|
||||
else if (strcmp("INVALID_KEY", ptr) == 0)
|
||||
result = i2p_error::invalid_key;
|
||||
else if (strcmp("INVALID_ID", ptr) == 0)
|
||||
result = i2p_error::invalid_id;
|
||||
else if (strcmp("TIMEOUT", ptr) == 0)
|
||||
result = i2p_error::timeout;
|
||||
else if (strcmp("KEY_NOT_FOUND", ptr) == 0)
|
||||
result = i2p_error::key_not_found;
|
||||
else
|
||||
result = i2p_error::num_errors; // unknown error
|
||||
}
|
||||
else if (strcmp("MESSAGE", name) == 0)
|
||||
{
|
||||
message = ptr;
|
||||
}
|
||||
else if (strcmp("VERSION", name) == 0)
|
||||
{
|
||||
version = atof(ptr);
|
||||
}
|
||||
else if (strcmp("VALUE", name) == 0)
|
||||
{
|
||||
m_name_lookup = ptr;
|
||||
}
|
||||
else if (strcmp("DESTINATION", name) == 0)
|
||||
{
|
||||
m_dest = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != i2p_error::no_error)
|
||||
{
|
||||
error_code ec(result, i2p_category);
|
||||
handle_error(ec, h);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case read_hello_response:
|
||||
switch (m_command)
|
||||
{
|
||||
case cmd_create_session:
|
||||
send_session_create(h);
|
||||
break;
|
||||
case cmd_accept:
|
||||
send_accept(h);
|
||||
break;
|
||||
case cmd_connect:
|
||||
send_connect(h);
|
||||
break;
|
||||
default:
|
||||
(*h)(e);
|
||||
std::vector<char>().swap(m_buffer);
|
||||
}
|
||||
break;
|
||||
case read_connect_response:
|
||||
case read_session_create_response:
|
||||
case read_name_lookup_response:
|
||||
(*h)(e);
|
||||
std::vector<char>().swap(m_buffer);
|
||||
break;
|
||||
case read_accept_response:
|
||||
// the SAM bridge is waiting for an incoming
|
||||
// connection.
|
||||
// wait for one more line containing
|
||||
// the destination of the remote peer
|
||||
m_command = cmd_incoming;
|
||||
m_buffer.resize(1);
|
||||
async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&i2p_stream::read_line, this, _1, h));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void i2p_stream::send_connect(boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
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);
|
||||
async_write(m_sock, asio::buffer(cmd, size)
|
||||
, boost::bind(&i2p_stream::start_read_line, this, _1, h));
|
||||
}
|
||||
|
||||
void i2p_stream::send_accept(boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
m_state = read_accept_response;
|
||||
char cmd[400];
|
||||
int size = snprintf(cmd, sizeof(cmd), "STREAM ACCEPT ID=%s\n", m_id);
|
||||
// fputs(cmd, stderr);
|
||||
async_write(m_sock, asio::buffer(cmd, size)
|
||||
, boost::bind(&i2p_stream::start_read_line, this, _1, h));
|
||||
}
|
||||
|
||||
void i2p_stream::send_session_create(boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
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);
|
||||
async_write(m_sock, asio::buffer(cmd, size)
|
||||
, boost::bind(&i2p_stream::start_read_line, this, _1, h));
|
||||
}
|
||||
|
||||
void i2p_stream::send_name_lookup(boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
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);
|
||||
async_write(m_sock, asio::buffer(cmd, size)
|
||||
, boost::bind(&i2p_stream::start_read_line, this, _1, h));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -67,6 +67,13 @@ namespace libtorrent
|
|||
if (ps.type == proxy_settings::socks4)
|
||||
s.get<socks5_stream>()->set_version(4);
|
||||
}
|
||||
#if TORRENT_USE_I2P
|
||||
else if (ps.type == proxy_settings::i2p_proxy)
|
||||
{
|
||||
s.instantiate<i2p_stream>(ios);
|
||||
s.get<i2p_stream>()->set_proxy(ps.hostname, ps.port);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -150,6 +150,14 @@ namespace libtorrent
|
|||
, m_received_in_piece(0)
|
||||
#endif
|
||||
{
|
||||
#if TORRENT_USE_I2P
|
||||
if (peerinfo && peerinfo->is_i2p_addr)
|
||||
{
|
||||
// quadruple the timeout for i2p peers
|
||||
m_timeout *= 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_channel_state[upload_channel] = peer_info::bw_idle;
|
||||
m_channel_state[download_channel] = peer_info::bw_idle;
|
||||
|
||||
|
@ -271,6 +279,14 @@ namespace libtorrent
|
|||
, m_received_in_piece(0)
|
||||
#endif
|
||||
{
|
||||
#if TORRENT_USE_I2P
|
||||
if (peerinfo && peerinfo->is_i2p_addr)
|
||||
{
|
||||
// quadruple the timeout for i2p peers
|
||||
m_timeout *= 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_channel_state[upload_channel] = peer_info::bw_idle;
|
||||
m_channel_state[download_channel] = peer_info::bw_idle;
|
||||
|
||||
|
@ -938,6 +954,18 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
i2p_stream* i2ps = m_socket->get<i2p_stream>();
|
||||
if (!i2ps && t->torrent_file().is_i2p() && !m_ses.m_settings.allow_i2p_mixed)
|
||||
{
|
||||
// the torrent is an i2p torrent, the peer is a regular peer
|
||||
// and we don't allow mixed mode. Disconnect the peer.
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << " rejected regular connection to i2p torrent\n";
|
||||
#endif
|
||||
disconnect(error_code(errors::peer_banned, libtorrent_category), 2);
|
||||
return;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(m_torrent.expired());
|
||||
// check to make sure we don't have another connection with the same
|
||||
// info_hash and peer_id. If we do. close this connection.
|
||||
|
|
272
src/policy.cpp
272
src/policy.cpp
|
@ -355,6 +355,12 @@ namespace libtorrent
|
|||
m_torrent->session().m_ipv6_peer_pool.destroy(
|
||||
static_cast<ipv6_peer*>(*i));
|
||||
else
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
if ((*i)->is_i2p_addr)
|
||||
m_torrent->session().m_i2p_peer_pool.destroy(
|
||||
static_cast<i2p_peer*>(*i));
|
||||
else
|
||||
#endif
|
||||
m_torrent->session().m_ipv4_peer_pool.destroy(
|
||||
static_cast<ipv4_peer*>(*i));
|
||||
|
@ -512,7 +518,7 @@ namespace libtorrent
|
|||
for (int iterations = (std::min)(int(m_peers.size()), 300);
|
||||
iterations > 0; --iterations)
|
||||
{
|
||||
if (m_round_robin == m_peers.size()) m_round_robin = 0;
|
||||
if (m_round_robin == int(m_peers.size())) m_round_robin = 0;
|
||||
|
||||
peer& pe = *m_peers[m_round_robin];
|
||||
int current = m_round_robin;
|
||||
|
@ -878,6 +884,156 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_num_seeds <= m_peers.size());
|
||||
}
|
||||
|
||||
bool policy::insert_peer(policy::peer* p, iterator iter, int flags)
|
||||
{
|
||||
TORRENT_ASSERT(p);
|
||||
|
||||
int max_peerlist_size = m_torrent->is_paused()
|
||||
?m_torrent->settings().max_paused_peerlist_size
|
||||
:m_torrent->settings().max_peerlist_size;
|
||||
|
||||
if (max_peerlist_size
|
||||
&& int(m_peers.size()) >= max_peerlist_size)
|
||||
{
|
||||
if (p->source == peer_info::resume_data) return false;
|
||||
|
||||
erase_peers();
|
||||
if (int(m_peers.size()) >= max_peerlist_size)
|
||||
return 0;
|
||||
|
||||
// since some peers were removed, we need to
|
||||
// update the iterator to make it valid again
|
||||
#if TORRENT_USE_I2P
|
||||
if (p->is_i2p_addr)
|
||||
{
|
||||
iter = std::lower_bound(
|
||||
m_peers.begin(), m_peers.end()
|
||||
, p->dest(), peer_address_compare());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
iter = std::lower_bound(
|
||||
m_peers.begin(), m_peers.end()
|
||||
, p->address(), peer_address_compare());
|
||||
}
|
||||
|
||||
if (m_round_robin > iter - m_peers.begin()) ++m_round_robin;
|
||||
|
||||
iter = m_peers.insert(iter, p);
|
||||
|
||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
if (flags & 0x01) p->pe_support = true;
|
||||
#endif
|
||||
if (flags & 0x02)
|
||||
{
|
||||
p->seed = true;
|
||||
++m_num_seeds;
|
||||
}
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
int as = ses.as_for_ip(remote.address());
|
||||
#ifdef TORRENT_DEBUG
|
||||
p->inet_as_num = as;
|
||||
#endif
|
||||
p->inet_as = ses.lookup_as(as);
|
||||
#endif
|
||||
if (is_connect_candidate(*p, m_finished))
|
||||
++m_num_connect_candidates;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void policy::update_peer(policy::peer* p, int src, int flags
|
||||
, tcp::endpoint const& remote, char const* destination)
|
||||
{
|
||||
bool was_conn_cand = is_connect_candidate(*p, m_finished);
|
||||
|
||||
p->connectable = true;
|
||||
|
||||
TORRENT_ASSERT(p->address() == remote.address());
|
||||
p->port = remote.port();
|
||||
p->source |= src;
|
||||
|
||||
// if this peer has failed before, decrease the
|
||||
// counter to allow it another try, since somebody
|
||||
// else is appearantly able to connect to it
|
||||
// only trust this if it comes from the tracker
|
||||
if (p->failcount > 0 && src == peer_info::tracker)
|
||||
--p->failcount;
|
||||
|
||||
// if we're connected to this peer
|
||||
// we already know if it's a seed or not
|
||||
// so we don't have to trust this source
|
||||
if ((flags & 0x02) && !p->connection)
|
||||
{
|
||||
if (!p->seed) ++m_num_seeds;
|
||||
p->seed = true;
|
||||
}
|
||||
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||
if (p->connection)
|
||||
{
|
||||
// this means we're already connected
|
||||
// to this peer. don't connect to
|
||||
// it again.
|
||||
|
||||
error_code ec;
|
||||
char hex_pid[41];
|
||||
to_hex((char*)&p->connection->pid()[0], 20, hex_pid);
|
||||
char msg[200];
|
||||
snprintf(msg, 200, "already connected to peer: %s %s"
|
||||
, print_endpoint(remote).c_str(), hex_pid);
|
||||
m_torrent->debug_log(msg);
|
||||
|
||||
TORRENT_ASSERT(p->connection->associated_torrent().lock().get() == m_torrent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (was_conn_cand != is_connect_candidate(*p, m_finished))
|
||||
{
|
||||
m_num_connect_candidates += was_conn_cand ? -1 : 1;
|
||||
if (m_num_connect_candidates < 0) m_num_connect_candidates = 0;
|
||||
}
|
||||
}
|
||||
|
||||
policy::peer* policy::add_i2p_peer(char const* destination, int src, char flags)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
aux::session_impl& ses = m_torrent->session();
|
||||
|
||||
bool found = false;
|
||||
iterator iter = std::lower_bound(
|
||||
m_peers.begin(), m_peers.end()
|
||||
, destination, peer_address_compare()
|
||||
);
|
||||
|
||||
if (iter != m_peers.end() && strcmp((*iter)->dest(), destination) == 0)
|
||||
found = true;
|
||||
|
||||
peer* p = 0;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// we don't have any info about this peer.
|
||||
// add a new entry
|
||||
p = (peer*)m_torrent->session().m_i2p_peer_pool.malloc();
|
||||
if (p == 0) return 0;
|
||||
m_torrent->session().m_i2p_peer_pool.set_next_size(500);
|
||||
new (p) i2p_peer(destination, true, src);
|
||||
if (!insert_peer(p, iter, flags))
|
||||
{
|
||||
m_torrent->session().m_i2p_peer_pool.free((i2p_peer*)p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = *iter;
|
||||
update_peer(p, src, flags, tcp::endpoint(), destination);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
policy::peer* policy::add_peer(tcp::endpoint const& remote, peer_id const& pid
|
||||
, int src, char flags)
|
||||
{
|
||||
|
@ -889,6 +1045,11 @@ namespace libtorrent
|
|||
|
||||
aux::session_impl& ses = m_torrent->session();
|
||||
|
||||
// if this is an i2p torrent, and we don't allow mixed mode
|
||||
// no regular peers should ever be added!
|
||||
if (!ses.m_settings.allow_i2p_mixed && m_torrent->torrent_file().is_i2p())
|
||||
return 0;
|
||||
|
||||
port_filter const& pf = ses.m_port_filter;
|
||||
if (pf.access(remote.port()) & port_filter::blocked)
|
||||
{
|
||||
|
@ -901,14 +1062,12 @@ namespace libtorrent
|
|||
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
|
||||
{
|
||||
if (ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
iterator iter;
|
||||
peer* i = 0;
|
||||
peer* p = 0;
|
||||
|
||||
int max_peerlist_size = m_torrent->is_paused()
|
||||
?m_torrent->settings().max_paused_peerlist_size
|
||||
|
@ -933,31 +1092,13 @@ namespace libtorrent
|
|||
|
||||
if (!found)
|
||||
{
|
||||
if (max_peerlist_size
|
||||
&& int(m_peers.size()) >= max_peerlist_size)
|
||||
{
|
||||
if (src == peer_info::resume_data) return 0;
|
||||
|
||||
erase_peers();
|
||||
if (int(m_peers.size()) >= max_peerlist_size)
|
||||
return 0;
|
||||
|
||||
// since some peers were removed, we need to
|
||||
// update the iterator to make it valid again
|
||||
iter = std::lower_bound(
|
||||
m_peers.begin(), m_peers.end()
|
||||
, remote.address(), peer_address_compare()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_round_robin > iter - m_peers.begin()) ++m_round_robin;
|
||||
|
||||
// we don't have any info about this peer.
|
||||
// add a new entry
|
||||
|
||||
#if TORRENT_USE_IPV6
|
||||
bool is_v6 = remote.address().is_v6();
|
||||
#endif
|
||||
peer* p =
|
||||
p =
|
||||
#if TORRENT_USE_IPV6
|
||||
is_v6 ? (peer*)m_torrent->session().m_ipv6_peer_pool.malloc() :
|
||||
#endif
|
||||
|
@ -977,83 +1118,23 @@ namespace libtorrent
|
|||
#endif
|
||||
new (p) ipv4_peer(remote, true, src);
|
||||
|
||||
iter = m_peers.insert(iter, p);
|
||||
|
||||
i = *iter;
|
||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
if (flags & 0x01) i->pe_support = true;
|
||||
#endif
|
||||
if (flags & 0x02)
|
||||
if (!insert_peer(p, iter, flags))
|
||||
{
|
||||
i->seed = true;
|
||||
++m_num_seeds;
|
||||
#if TORRENT_USE_IPV6
|
||||
if (is_v6) m_torrent->session().m_ipv6_peer_pool.free((ipv6_peer*)p);
|
||||
else
|
||||
#endif
|
||||
m_torrent->session().m_ipv4_peer_pool.free((ipv4_peer*)p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
int as = ses.as_for_ip(remote.address());
|
||||
#ifdef TORRENT_DEBUG
|
||||
i->inet_as_num = as;
|
||||
#endif
|
||||
i->inet_as = ses.lookup_as(as);
|
||||
#endif
|
||||
if (is_connect_candidate(*i, m_finished))
|
||||
++m_num_connect_candidates;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = *iter;
|
||||
|
||||
bool was_conn_cand = is_connect_candidate(*i, m_finished);
|
||||
|
||||
i->connectable = true;
|
||||
|
||||
TORRENT_ASSERT(i->address() == remote.address());
|
||||
i->port = remote.port();
|
||||
i->source |= src;
|
||||
|
||||
// if this peer has failed before, decrease the
|
||||
// counter to allow it another try, since somebody
|
||||
// else is appearantly able to connect to it
|
||||
// only trust this if it comes from the tracker
|
||||
if (i->failcount > 0 && src == peer_info::tracker)
|
||||
--i->failcount;
|
||||
|
||||
// if we're connected to this peer
|
||||
// we already know if it's a seed or not
|
||||
// so we don't have to trust this source
|
||||
if ((flags & 0x02) && !i->connection)
|
||||
{
|
||||
if (!i->seed) ++m_num_seeds;
|
||||
i->seed = true;
|
||||
}
|
||||
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||
if (i->connection)
|
||||
{
|
||||
// this means we're already connected
|
||||
// to this peer. don't connect to
|
||||
// it again.
|
||||
|
||||
error_code ec;
|
||||
char hex_pid[41];
|
||||
to_hex((char*)&i->connection->pid()[0], 20, hex_pid);
|
||||
char msg[200];
|
||||
snprintf(msg, 200, "already connected to peer: %s %s"
|
||||
, print_endpoint(remote).c_str(), hex_pid);
|
||||
m_torrent->debug_log(msg);
|
||||
|
||||
TORRENT_ASSERT(i->connection->associated_torrent().lock().get() == m_torrent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (was_conn_cand != is_connect_candidate(*i, m_finished))
|
||||
{
|
||||
m_num_connect_candidates += was_conn_cand ? -1 : 1;
|
||||
if (m_num_connect_candidates < 0) m_num_connect_candidates = 0;
|
||||
}
|
||||
p = *iter;
|
||||
update_peer(p, src, flags, remote, 0);
|
||||
}
|
||||
|
||||
return i;
|
||||
return p;
|
||||
}
|
||||
|
||||
bool policy::connect_one_peer(int session_time)
|
||||
|
@ -1326,6 +1407,9 @@ namespace libtorrent
|
|||
#endif
|
||||
#if TORRENT_USE_IPV6
|
||||
, is_v6_addr(false)
|
||||
#endif
|
||||
#if TORRENT_USE_I2P
|
||||
, is_i2p_addr(false)
|
||||
#endif
|
||||
, on_parole(false)
|
||||
, banned(false)
|
||||
|
|
|
@ -715,6 +715,20 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void session::set_i2p_proxy(proxy_settings const& s)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_impl->m_mutex);
|
||||
m_impl->set_i2p_proxy(s);
|
||||
}
|
||||
|
||||
proxy_settings const& session::i2p_proxy() const
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_impl->m_mutex);
|
||||
return m_impl->i2p_proxy();
|
||||
}
|
||||
#endif
|
||||
|
||||
int session::max_uploads() const
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_impl->m_mutex);
|
||||
|
|
|
@ -192,6 +192,9 @@ namespace aux {
|
|||
#endif
|
||||
, m_tracker_manager(*this, m_tracker_proxy)
|
||||
, m_listen_port_retries(listen_port_range.second - listen_port_range.first)
|
||||
#if TORRENT_USE_I2P
|
||||
, m_i2p_conn(m_io_service)
|
||||
#endif
|
||||
, m_abort(false)
|
||||
, m_paused(false)
|
||||
, m_max_uploads(8)
|
||||
|
@ -524,6 +527,9 @@ namespace aux {
|
|||
#endif
|
||||
// abort the main thread
|
||||
m_abort = true;
|
||||
#if TORRENT_USE_I2P
|
||||
m_i2p_conn.close();
|
||||
#endif
|
||||
m_queued_for_checking.clear();
|
||||
if (m_lsd) m_lsd->close();
|
||||
if (m_upnp) m_upnp->close();
|
||||
|
@ -839,6 +845,9 @@ namespace aux {
|
|||
}
|
||||
|
||||
open_new_incoming_socks_connection();
|
||||
#if TORRENT_USE_I2P
|
||||
open_new_incoming_i2p_connection();
|
||||
#endif
|
||||
|
||||
if (!m_listen_sockets.empty())
|
||||
{
|
||||
|
@ -886,6 +895,47 @@ namespace aux {
|
|||
, boost::bind(&session_impl::on_socks_accept, this, m_socks_listen_socket, _1));
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void session_impl::on_i2p_open(error_code const& ec)
|
||||
{
|
||||
open_new_incoming_i2p_connection();
|
||||
}
|
||||
|
||||
void session_impl::open_new_incoming_i2p_connection()
|
||||
{
|
||||
if (!m_i2p_conn.is_open()) return;
|
||||
|
||||
if (m_i2p_listen_socket) return;
|
||||
|
||||
m_i2p_listen_socket = boost::shared_ptr<socket_type>(new socket_type(m_io_service));
|
||||
bool ret = instantiate_connection(m_io_service, m_i2p_conn.proxy()
|
||||
, *m_i2p_listen_socket);
|
||||
TORRENT_ASSERT(ret);
|
||||
|
||||
i2p_stream& s = *m_i2p_listen_socket->get<i2p_stream>();
|
||||
s.set_command(i2p_stream::cmd_accept);
|
||||
s.set_session_id(m_i2p_conn.session_id());
|
||||
s.async_connect(tcp::endpoint(address_v4::any(), m_listen_interface.port())
|
||||
, boost::bind(&session_impl::on_i2p_accept, this, m_i2p_listen_socket, _1));
|
||||
}
|
||||
|
||||
void session_impl::on_i2p_accept(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e)
|
||||
{
|
||||
m_i2p_listen_socket.reset();
|
||||
if (e == asio::error::operation_aborted) return;
|
||||
if (e)
|
||||
{
|
||||
if (m_alerts.should_post<listen_failed_alert>())
|
||||
m_alerts.post_alert(listen_failed_alert(tcp::endpoint(
|
||||
address_v4::any(), m_listen_interface.port()), e));
|
||||
return;
|
||||
}
|
||||
open_new_incoming_i2p_connection();
|
||||
incoming_connection(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
|
||||
void session_impl::on_receive_udp(error_code const& e
|
||||
|
@ -2323,7 +2373,8 @@ namespace aux {
|
|||
boost::shared_ptr<torrent> t = find_torrent(ih).lock();
|
||||
if (!t) return;
|
||||
// don't add peers from lsd to private torrents
|
||||
if (t->torrent_file().priv()) return;
|
||||
if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
|
||||
&& !m_settings.allow_i2p_mixed)) return;
|
||||
|
||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||
(*m_logger) << time_now_string()
|
||||
|
|
|
@ -1138,9 +1138,13 @@ namespace libtorrent
|
|||
if (m_abort) return;
|
||||
|
||||
TORRENT_ASSERT(!m_torrent_file->priv());
|
||||
if (m_torrent_file->is_valid() && m_torrent_file->priv())
|
||||
if (m_torrent_file->is_valid()
|
||||
&& (m_torrent_file->priv()
|
||||
|| (torrent_file().is_i2p()
|
||||
&& !m_settings.allow_i2p_mixed)))
|
||||
return;
|
||||
|
||||
|
||||
if (is_paused()) return;
|
||||
|
||||
boost::weak_ptr<torrent> self(shared_from_this());
|
||||
|
@ -1187,6 +1191,10 @@ namespace libtorrent
|
|||
m_ses.m_alerts.post_alert(dht_reply_alert(
|
||||
get_handle(), peers.size()));
|
||||
}
|
||||
|
||||
if (torrent_file().priv() || (torrent_file().is_i2p()
|
||||
&& !m_settings.allow_i2p_mixed)) return;
|
||||
|
||||
std::for_each(peers.begin(), peers.end(), bind(
|
||||
&policy::add_peer, boost::ref(m_policy), _1, peer_id(0)
|
||||
, peer_info::dht, 0));
|
||||
|
@ -1428,9 +1436,30 @@ namespace libtorrent
|
|||
// assume this is because we got a hostname instead of
|
||||
// an ip address from the tracker
|
||||
|
||||
tcp::resolver::query q(i->ip, to_string(i->port).elems);
|
||||
m_host_resolver.async_resolve(q,
|
||||
bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
|
||||
#if TORRENT_USE_I2P
|
||||
char const* top_domain = strrchr(i->ip.c_str(), '.');
|
||||
if (top_domain && strcmp(top_domain, ".i2p") == 0 && m_ses.m_i2p_conn.is_open())
|
||||
{
|
||||
// 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()
|
||||
, bind(&torrent::on_i2p_resolve
|
||||
, shared_from_this(), _1, _2));
|
||||
*/
|
||||
// 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
|
||||
i->ip.resize(i->ip.size() - 4);
|
||||
m_policy.add_i2p_peer(i->ip.c_str(), peer_info::tracker, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
tcp::resolver::query q(i->ip, to_string(i->port).elems);
|
||||
m_host_resolver.async_resolve(q,
|
||||
bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1483,6 +1512,19 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
void torrent::on_i2p_resolve(error_code const& ec, char const* dest)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (ec || m_ses.is_aborted()) return;
|
||||
|
||||
m_policy.add_i2p_peer(dest, peer_info::tracker, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
|
||||
, peer_id pid)
|
||||
{
|
||||
|
@ -1500,10 +1542,7 @@ namespace libtorrent
|
|||
debug_log("blocked ip from tracker: " + host->endpoint().address().to_string(ec));
|
||||
#endif
|
||||
if (m_ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
{
|
||||
m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3837,7 +3876,11 @@ namespace libtorrent
|
|||
peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
|
||||
, bind(&peer_connection::remote, _1) == peerinfo->ip());
|
||||
TORRENT_ASSERT(i_ == m_connections.end()
|
||||
|| dynamic_cast<bt_peer_connection*>(*i_) == 0);
|
||||
|| dynamic_cast<bt_peer_connection*>(*i_) == 0
|
||||
#if TORRENT_USE_I2P
|
||||
|| peerinfo->is_i2p_addr
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
TORRENT_ASSERT(want_more_peers());
|
||||
|
@ -3848,9 +3891,24 @@ namespace libtorrent
|
|||
|
||||
boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
|
||||
|
||||
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
|
||||
(void)ret;
|
||||
TORRENT_ASSERT(ret);
|
||||
#if TORRENT_USE_I2P
|
||||
bool i2p = peerinfo->is_i2p_addr;
|
||||
if (i2p)
|
||||
{
|
||||
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.i2p_proxy(), *s);
|
||||
(void)ret;
|
||||
TORRENT_ASSERT(ret);
|
||||
s->get<i2p_stream>()->set_destination(static_cast<policy::i2p_peer*>(peerinfo)->destination);
|
||||
s->get<i2p_stream>()->set_command(i2p_stream::cmd_connect);
|
||||
s->get<i2p_stream>()->set_session_id(m_ses.m_i2p_conn.session_id());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
|
||||
(void)ret;
|
||||
TORRENT_ASSERT(ret);
|
||||
}
|
||||
|
||||
m_ses.setup_socket_buffers(*s);
|
||||
|
||||
|
@ -5068,7 +5126,10 @@ namespace libtorrent
|
|||
|
||||
// private torrents are never announced on LSD
|
||||
// or on DHT, we don't need this timer.
|
||||
if (!m_torrent_file->is_valid() || !m_torrent_file->priv())
|
||||
if (!m_torrent_file->is_valid()
|
||||
|| (!m_torrent_file->priv()
|
||||
&& (!m_torrent_file->is_i2p()
|
||||
|| m_settings.allow_i2p_mixed)))
|
||||
{
|
||||
error_code ec;
|
||||
boost::weak_ptr<torrent> self(shared_from_this());
|
||||
|
|
|
@ -62,6 +62,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/utf8.hpp"
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
#include "libtorrent/parse_url.hpp"
|
||||
#endif
|
||||
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
namespace libtorrent
|
||||
|
@ -366,6 +370,7 @@ namespace libtorrent
|
|||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_i2p(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
, m_merkle_first_leaf(0)
|
||||
|
@ -579,6 +584,7 @@ namespace libtorrent
|
|||
m_created_by.swap(ti.m_created_by);
|
||||
swap(m_multifile, ti.m_multifile);
|
||||
swap(m_private, ti.m_private);
|
||||
swap(m_i2p, ti.m_i2p);
|
||||
swap(m_info_section, ti.m_info_section);
|
||||
swap(m_info_section_size, ti.m_info_section_size);
|
||||
swap(m_piece_hashes, ti.m_piece_hashes);
|
||||
|
@ -813,6 +819,19 @@ namespace libtorrent
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
bool is_i2p_url(std::string const& url)
|
||||
{
|
||||
using boost::tuples::ignore;
|
||||
std::string hostname;
|
||||
error_code ec;
|
||||
boost::tie(ignore, ignore, hostname, ignore, ignore)
|
||||
= parse_url_components(url, ec);
|
||||
char const* top_domain = strrchr(hostname.c_str(), '.');
|
||||
return top_domain && strcmp(top_domain, ".i2p") == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, error_code& ec)
|
||||
{
|
||||
if (torrent_file.type() != lazy_entry::dict_t)
|
||||
|
@ -838,6 +857,9 @@ namespace libtorrent
|
|||
e.fail_limit = 0;
|
||||
e.source = announce_entry::source_torrent;
|
||||
e.trim();
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p_url(e.url)) m_i2p = true;
|
||||
#endif
|
||||
m_urls.push_back(e);
|
||||
}
|
||||
}
|
||||
|
@ -868,6 +890,9 @@ namespace libtorrent
|
|||
e.fail_limit = 0;
|
||||
e.source = announce_entry::source_torrent;
|
||||
e.trim();
|
||||
#if TORRENT_USE_I2P
|
||||
if (is_i2p_url(e.url)) m_i2p = true;
|
||||
#endif
|
||||
if (!e.url.empty()) m_urls.push_back(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -234,7 +234,11 @@ namespace libtorrent
|
|||
{
|
||||
con = new http_tracker_connection(
|
||||
ios, cc, *this, req, c
|
||||
, m_ses, m_proxy, auth);
|
||||
, m_ses, m_proxy, auth
|
||||
#if TORRENT_USE_I2P
|
||||
, &m_ses.m_i2p_conn
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else if (protocol == "udp")
|
||||
{
|
||||
|
|
|
@ -436,7 +436,8 @@ namespace libtorrent
|
|||
|
||||
boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
|
||||
{
|
||||
if (t->torrent_file().priv())
|
||||
if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
|
||||
&& !t->settings().allow_i2p_mixed))
|
||||
{
|
||||
return boost::shared_ptr<torrent_plugin>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue