diff --git a/ChangeLog b/ChangeLog
index 8db6ceb19..d25d12545 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -73,6 +73,9 @@
* require C++11 to build libtorrent
+ * bind upnp requests to correct local address
+ * save resume data when removing web seeds
+ * fix proxying of https connections
* fix race condition in disk I/O storage class
* fix http connection timeout on multi-homed hosts
* removed depdendency on boost::uintptr_t for better compatibility
diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp
index b27c88880..9de59b56f 100644
--- a/include/libtorrent/http_connection.hpp
+++ b/include/libtorrent/http_connection.hpp
@@ -100,7 +100,7 @@ struct TORRENT_EXTRA_EXPORT http_connection
std::string m_sendbuffer;
void get(std::string const& url, time_duration timeout = seconds(30)
- , int prio = 0, aux::proxy_settings const* ps = 0, int handle_redirects = 5
+ , int prio = 0, aux::proxy_settings const* ps = NULL, int handle_redirects = 5
, std::string const& user_agent = std::string()
, boost::optional
const& bind_addr = boost::optional()
, int resolve_flags = 0, std::string const& auth_ = std::string()
@@ -110,7 +110,7 @@ struct TORRENT_EXTRA_EXPORT http_connection
);
void start(std::string const& hostname, int port
- , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = 0
+ , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = NULL
, bool ssl = false, int handle_redirect = 5
, boost::optional const& bind_addr = boost::optional()
, int resolve_flags = 0
diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp
index 1a9742e3d..57345fc01 100644
--- a/include/libtorrent/natpmp.hpp
+++ b/include/libtorrent/natpmp.hpp
@@ -55,7 +55,7 @@ struct TORRENT_EXTRA_EXPORT natpmp
// maps the ports, if a port is set to 0
// it will not be mapped
- int add_mapping(aux::portmap_protocol p, int external_port, int local_port);
+ int add_mapping(aux::portmap_protocol p, int external_port, tcp::endpoint local_ep);
void delete_mapping(int mapping_index);
bool get_mapping(int mapping_index, int& local_port, int& external_port
, aux::portmap_protocol& protocol) const;
diff --git a/include/libtorrent/proxy_base.hpp b/include/libtorrent/proxy_base.hpp
index 76b1f7c46..fd1622574 100644
--- a/include/libtorrent/proxy_base.hpp
+++ b/include/libtorrent/proxy_base.hpp
@@ -249,8 +249,8 @@ protected:
bool handle_error(error_code const& e, handler_type const& h);
tcp::socket m_sock;
- std::string m_hostname;
- int m_port;
+ std::string m_hostname; // proxy host
+ int m_port; // proxy port
endpoint_type m_remote_endpoint;
diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp
index d207760a7..9d053a39c 100644
--- a/include/libtorrent/upnp.hpp
+++ b/include/libtorrent/upnp.hpp
@@ -172,13 +172,13 @@ struct TORRENT_EXTRA_EXPORT upnp final
// portmap_alert_ respectively. If The mapping fails immediately, the return value
// is -1, which means failure. There will not be any error alert notification for
// mappings that fail with a -1 return value.
- int add_mapping(aux::portmap_protocol p, int external_port, int local_port);
+ int add_mapping(aux::portmap_protocol p, int external_port, tcp::endpoint local_ep);
// This function removes a port mapping. ``mapping_index`` is the index that refers
// to the mapping you want to remove, which was returned from add_mapping().
void delete_mapping(int mapping_index);
- bool get_mapping(int mapping_index, int& local_port, int& external_port
+ bool get_mapping(int mapping_index, tcp::endpoint& local_ep, int& external_port
, aux::portmap_protocol& protocol) const;
void discover_device();
@@ -249,7 +249,7 @@ private:
{
aux::portmap_protocol protocol = aux::portmap_protocol::none;
int external_port = 0;
- int local_port = 0;
+ tcp::endpoint local_ep;
};
struct mapping_t
@@ -263,7 +263,7 @@ private:
// the local port for this mapping. If this is set
// to 0, the mapping is not in use
- int local_port = 0;
+ tcp::endpoint local_ep;
// the external (on the NAT router) port
// for the mapping. This is the port we
diff --git a/simulation/libsimulator b/simulation/libsimulator
index 0e8d74baf..70feadef8 160000
--- a/simulation/libsimulator
+++ b/simulation/libsimulator
@@ -1 +1 @@
-Subproject commit 0e8d74baf1f6d9db19857eaa87734faecd530f94
+Subproject commit 70feadef80dc76ae6d5e7c2f92334377d698dd7d
diff --git a/simulation/test_http_connection.cpp b/simulation/test_http_connection.cpp
index f301448cb..e813a2f7c 100644
--- a/simulation/test_http_connection.cpp
+++ b/simulation/test_http_connection.cpp
@@ -602,6 +602,53 @@ TORRENT_TEST(http_connection_http_error)
test_proxy_failure(settings_pack::http);
}
+// Requests a proxied SSL connection. This test just ensures that the correct CONNECT request
+// is sent to the proxy server.
+TORRENT_TEST(http_connection_ssl_proxy)
+{
+ using sim::asio::ip::address_v4;
+ sim_config network_cfg;
+ sim::simulation sim{network_cfg};
+
+ sim::asio::io_service client_ios(sim, address_v4::from_string("10.0.0.1"));
+ sim::asio::io_service proxy_ios(sim, address_v4::from_string("50.50.50.50"));
+ lt::resolver res(client_ios);
+
+ sim::http_server http_proxy(proxy_ios, 4445);
+
+ lt::aux::proxy_settings ps = make_proxy_settings(settings_pack::http);
+
+ int client_counter = 0;
+ int proxy_counter = 0;
+
+ http_proxy.register_handler("10.0.0.2:8080"
+ , [&proxy_counter](std::string method, std::string req, std::map& headers)
+ {
+ proxy_counter++;
+ TEST_EQUAL(method, "CONNECT");
+ return sim::send_response(403, "Not supported", 1337);
+ });
+
+ auto h = std::make_shared(client_ios
+ , res
+ , [&client_counter](error_code const& ec, http_parser const& parser
+ , char const* data, const int size, http_connection& c)
+ {
+ client_counter++;
+ TEST_EQUAL(ec, boost::asio::error::operation_not_supported);
+ });
+
+ h->start("10.0.0.2", 8080, seconds(1), 0, &ps, true /*ssl*/);
+
+ error_code e;
+ sim.run(e);
+
+ TEST_EQUAL(client_counter, 1);
+ TEST_EQUAL(proxy_counter, 1);
+ if (e) std::cerr << " run failed: " << e.message() << std::endl;
+ TEST_EQUAL(e, error_code());
+}
+
// TODO: test http proxy with password
// TODO: test socks5 with password
// TODO: test SSL
diff --git a/src/http_stream.cpp b/src/http_stream.cpp
index 982c60dca..d2da3ed80 100644
--- a/src/http_stream.cpp
+++ b/src/http_stream.cpp
@@ -64,15 +64,7 @@ namespace libtorrent {
// send CONNECT
std::back_insert_iterator> p(m_buffer);
- std::string endpoint;
- if (!m_hostname.empty())
- {
- endpoint = m_hostname + ':' + to_string(m_remote_endpoint.port()).data();
- }
- else
- {
- endpoint = print_endpoint(m_remote_endpoint);
- }
+ std::string const endpoint = print_endpoint(m_remote_endpoint);
write_string("CONNECT " + endpoint + " HTTP/1.0\r\n", p);
if (!m_user.empty())
{
diff --git a/src/natpmp.cpp b/src/natpmp.cpp
index 3cc84794e..5546d9413 100644
--- a/src/natpmp.cpp
+++ b/src/natpmp.cpp
@@ -229,7 +229,7 @@ void natpmp::delete_mapping(int const index)
}
int natpmp::add_mapping(portmap_protocol const p, int const external_port
- , int const local_port)
+ , tcp::endpoint const local_ep)
{
TORRENT_ASSERT(is_single_thread());
@@ -244,7 +244,7 @@ int natpmp::add_mapping(portmap_protocol const p, int const external_port
}
i->protocol = p;
i->external_port = external_port;
- i->local_port = local_port;
+ i->local_port = local_ep.port();
i->act = mapping_t::action::add;
int const mapping_index = int(i - m_mappings.begin());
diff --git a/src/session_impl.cpp b/src/session_impl.cpp
index 6193bb638..148fa95ae 100644
--- a/src/session_impl.cpp
+++ b/src/session_impl.cpp
@@ -1528,7 +1528,7 @@ namespace {
}
#endif // TORRENT_DISABLE_LOGGING
}
-#endif // TORRENT_WINDOWS
+#else
{
// this is best-effort. ignore errors
@@ -1542,6 +1542,7 @@ namespace {
}
#endif // TORRENT_DISABLE_LOGGING
}
+#endif // TORRENT_WINDOWS
#if TORRENT_USE_IPV6
if (bind_ep.address().is_v6())
@@ -2200,7 +2201,12 @@ namespace {
// only update this mapping if we actually have a socket listening
if (ep != EndpointType())
- map_handle = m.add_mapping(protocol, ep.port(), ep.port());
+ map_handle = m.add_mapping(protocol, ep.port(), ep);
+ }
+
+ tcp::endpoint to_tcp(udp::endpoint const ep)
+ {
+ return tcp::endpoint(ep.address(), ep.port());
}
}
@@ -2213,12 +2219,12 @@ namespace {
if ((mask & remap_natpmp) && m_natpmp)
{
map_port(*m_natpmp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]);
- map_port(*m_natpmp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[0]);
+ map_port(*m_natpmp, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[0]);
}
if ((mask & remap_upnp) && m_upnp)
{
map_port(*m_upnp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[1]);
- map_port(*m_upnp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[1]);
+ map_port(*m_upnp, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[1]);
}
}
@@ -5011,8 +5017,9 @@ namespace {
{
#ifdef TORRENT_WINDOWS
s.set_option(exclusive_address_use(true), ec);
-#endif
+#else
s.set_option(tcp::acceptor::reuse_address(true), ec);
+#endif
// ignore errors because the underlying socket may not
// be opened yet. This happens when we're routing through
// a proxy. In that case, we don't yet know the address of
@@ -6613,9 +6620,9 @@ namespace {
{
int ret = 0;
if (m_upnp) ret = m_upnp->add_mapping(static_cast(t), external_port
- , local_port);
+ , tcp::endpoint({}, static_cast(local_port)));
if (m_natpmp) ret = m_natpmp->add_mapping(static_cast(t), external_port
- , local_port);
+ , tcp::endpoint({}, static_cast(local_port)));
return ret;
}
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 7a29f23e6..94d4ee127 100644
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -9776,7 +9776,11 @@ namespace libtorrent {
auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end()
, [&] (web_seed_t const& w) { return w.url == url && w.type == type; });
- if (i != m_web_seeds.end()) remove_web_seed_iter(i);
+ if (i != m_web_seeds.end())
+ {
+ remove_web_seed_iter(i);
+ set_need_save_resume();
+ }
}
void torrent::disconnect_web_seed(peer_connection* p)
diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp
index 839ca35b5..0e8cac571 100644
--- a/src/udp_socket.cpp
+++ b/src/udp_socket.cpp
@@ -433,8 +433,9 @@ void udp_socket::open(udp const& protocol, error_code& ec)
error_code err;
#ifdef TORRENT_WINDOWS
m_socket.set_option(exclusive_address_use(true), err);
-#endif
+#else
m_socket.set_option(boost::asio::socket_base::reuse_address(true), err);
+#endif
}
void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
diff --git a/src/upnp.cpp b/src/upnp.cpp
index 8558f8bd7..54f02e257 100644
--- a/src/upnp.cpp
+++ b/src/upnp.cpp
@@ -182,7 +182,7 @@ void upnp::discover_device_impl()
// returns a reference to a mapping or -1 on failure
int upnp::add_mapping(portmap_protocol const p, int const external_port
- , int const local_port)
+ , tcp::endpoint const local_ep)
{
TORRENT_ASSERT(is_single_thread());
// external port 0 means _every_ port
@@ -190,9 +190,9 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port
#ifndef TORRENT_DISABLE_LOGGING
log("adding port map: [ protocol: %s ext_port: %u "
- "local_port: %u ] %s", (p == portmap_protocol::tcp?"tcp":"udp")
+ "local_ep: %s ] %s", (p == portmap_protocol::tcp?"tcp":"udp")
, external_port
- , local_port, m_disabled ? "DISABLED": "");
+ , print_endpoint(local_ep).c_str(), m_disabled ? "DISABLED": "");
#endif
if (m_disabled) return -1;
@@ -208,7 +208,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port
mapping_it->protocol = p;
mapping_it->external_port = external_port;
- mapping_it->local_port = local_port;
+ mapping_it->local_ep = local_ep;
int const mapping_index = int(mapping_it - m_mappings.begin());
@@ -224,7 +224,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port
m.act = mapping_t::action::add;
m.protocol = p;
m.external_port = external_port;
- m.local_port = local_port;
+ m.local_ep = local_ep;
if (!d.service_namespace.empty()) update_map(d, mapping_index);
}
@@ -242,8 +242,8 @@ void upnp::delete_mapping(int const mapping)
#ifndef TORRENT_DISABLE_LOGGING
log("deleting port map: [ protocol: %s ext_port: %u "
- "local_port: %u ]", (m.protocol == portmap_protocol::tcp?"tcp":"udp"), m.external_port
- , m.local_port);
+ "local_ep: %s ]", (m.protocol == portmap_protocol::tcp?"tcp":"udp"), m.external_port
+ , print_endpoint(m.local_ep).c_str());
#endif
if (m.protocol == portmap_protocol::none) return;
@@ -261,7 +261,7 @@ void upnp::delete_mapping(int const mapping)
}
bool upnp::get_mapping(int const index
- , int& local_port
+ , tcp::endpoint& local_ep
, int& external_port
, portmap_protocol& protocol) const
{
@@ -270,7 +270,7 @@ bool upnp::get_mapping(int const index
if (index >= int(m_mappings.size()) || index < 0) return false;
global_mapping_t const& m = m_mappings[index];
if (m.protocol == portmap_protocol::none) return false;
- local_port = m.local_port;
+ local_ep = m.local_ep;
external_port = m.external_port;
protocol = m.protocol;
return true;
@@ -586,7 +586,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
{
mapping_t m;
m.act = mapping_t::action::add;
- m.local_port = j.local_port;
+ m.local_ep = j.local_ep;
m.external_port = j.external_port;
m.protocol = j.protocol;
d.mapping.push_back(m);
@@ -744,9 +744,9 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int const i)
""
, soap_action, d.service_namespace.c_str(), d.mapping[i].external_port
, (d.mapping[i].protocol == portmap_protocol::udp ? "UDP" : "TCP")
- , d.mapping[i].local_port
+ , d.mapping[i].local_ep.port()
, local_endpoint.c_str()
- , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_port
+ , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_ep.port()
, d.lease_duration, soap_action);
post(d, soap, soap_action);
@@ -817,7 +817,7 @@ void upnp::update_map(rootdevice& d, int const i)
, std::bind(&upnp::create_port_mapping, self(), _1, std::ref(d), i));
d.upnp_connection->start(d.hostname, d.port
- , seconds(10), 1);
+ , seconds(10), 1, NULL, false, 5, m.local_ep.address());
}
else if (m.act == mapping_t::action::del)
{
@@ -828,7 +828,7 @@ void upnp::update_map(rootdevice& d, int const i)
, std::ref(d), i, _5), true, default_max_bottled_buffer_size
, std::bind(&upnp::delete_port_mapping, self(), std::ref(d), i));
d.upnp_connection->start(d.hostname, d.port
- , seconds(10), 1);
+ , seconds(10), 1, NULL, false, 5, m.local_ep.address());
}
m.act = mapping_t::action::none;
diff --git a/test/test_dht.cpp b/test/test_dht.cpp
index 631a8289b..8379531ae 100644
--- a/test/test_dht.cpp
+++ b/test/test_dht.cpp
@@ -135,6 +135,7 @@ struct mock_dht_socket final : aux::session_listen_socket
tcp::endpoint m_local_endpoint;
};
+#if TORRENT_USE_IPV6
struct mock_dht_socket6 final : aux::session_listen_socket
{
address get_external_address() override { return m_external_address; }
@@ -143,6 +144,7 @@ struct mock_dht_socket6 final : aux::session_listen_socket
address m_external_address = addr6("2002::1");
tcp::endpoint m_local_endpoint = tcp::endpoint(addr6("2002::1"), 6881);
};
+#endif
node* get_foreign_node_stub(node_id const&, std::string const&)
{
diff --git a/test/test_natpmp.cpp b/test/test_natpmp.cpp
index 75205a715..61c5dde67 100644
--- a/test/test_natpmp.cpp
+++ b/test/test_natpmp.cpp
@@ -87,8 +87,9 @@ int main(int argc, char* argv[])
deadline_timer timer(ios);
int const tcp_map = natpmp_handler->add_mapping(portmap_protocol::tcp
- , atoi(argv[1]), atoi(argv[1]));
- natpmp_handler->add_mapping(portmap_protocol::udp, atoi(argv[2]), atoi(argv[2]));
+ , atoi(argv[1]), tcp::endpoint({}, atoi(argv[1])));
+ natpmp_handler->add_mapping(portmap_protocol::udp, atoi(argv[2])
+ , tcp::endpoint({}, atoi(argv[2])));
error_code ec;
timer.expires_from_now(seconds(2), ec);
diff --git a/test/test_session_params.cpp b/test/test_session_params.cpp
index 7102919df..80588724f 100644
--- a/test/test_session_params.cpp
+++ b/test/test_session_params.cpp
@@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp"
#include "libtorrent/bdecode.hpp"
#include "libtorrent/hex.hpp"
+#include "setup_transfer.hpp" // for addr6
#include "settings.hpp"
#include "test.hpp"
@@ -112,8 +113,10 @@ TORRENT_TEST(dht_state)
s.nids.emplace_back(addr4("0.0.0.0"), to_hash("0000000000000000000000000000000000000001"));
s.nodes.push_back(uep("1.1.1.1", 1));
s.nodes.push_back(uep("2.2.2.2", 2));
+#if TORRENT_USE_IPV6
// not important that IPv6 is disabled here
s.nids.emplace_back(addr6("::"), to_hash("0000000000000000000000000000000000000002"));
+#endif
session_params params(p);
params.dht_settings = sett;
diff --git a/test/test_upnp.cpp b/test/test_upnp.cpp
index 039283093..c992d5296 100644
--- a/test/test_upnp.cpp
+++ b/test/test_upnp.cpp
@@ -198,8 +198,8 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con
std::cout << "router: " << upnp_handler->router_model() << std::endl;
TEST_EQUAL(upnp_handler->router_model(), router_model);
- int mapping1 = upnp_handler->add_mapping(portmap_protocol::tcp, 500, 500);
- int mapping2 = upnp_handler->add_mapping(portmap_protocol::udp, 501, 501);
+ int const mapping1 = upnp_handler->add_mapping(portmap_protocol::tcp, 500, ep("127.0.0.1", 500));
+ int const mapping2 = upnp_handler->add_mapping(portmap_protocol::udp, 501, ep("127.0.0.1", 501));
for (int i = 0; i < 40; ++i)
{