support requesting UPnP and NAT-PMP routers for our external IP address
This commit is contained in:
@@ -3992,6 +3992,8 @@ session_settings
|
|||||||
bool rate_limit_utp;
|
bool rate_limit_utp;
|
||||||
|
|
||||||
int listen_queue_size;
|
int listen_queue_size;
|
||||||
|
|
||||||
|
bool announce_double_nat;
|
||||||
};
|
};
|
||||||
|
|
||||||
``version`` is automatically set to the libtorrent version you're using
|
``version`` is automatically set to the libtorrent version you're using
|
||||||
@@ -4790,6 +4792,10 @@ expects to receive a lot of connections, or used in a simulator or test, it
|
|||||||
might make sense to raise this number. It will not take affect until listen_on()
|
might make sense to raise this number. It will not take affect until listen_on()
|
||||||
is called again (or for the first time).
|
is called again (or for the first time).
|
||||||
|
|
||||||
|
if ``announce_double_nat`` is true, the ``&ip=`` argument in tracker requests
|
||||||
|
(unless otherwise specified) will be set to the intermediate IP address, if the
|
||||||
|
user is double NATed. If ther user is not double NATed, this option has no affect.
|
||||||
|
|
||||||
pe_settings
|
pe_settings
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@@ -235,8 +235,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
// called when a port mapping is successful, or a router returns
|
// called when a port mapping is successful, or a router returns
|
||||||
// a failure to map a port
|
// a failure to map a port
|
||||||
void on_port_mapping(int mapping, int port, error_code const& ec
|
void on_port_mapping(int mapping, address const& ip, int port
|
||||||
, int nat_transport);
|
, error_code const& ec, int nat_transport);
|
||||||
|
|
||||||
bool is_aborted() const { return m_abort; }
|
bool is_aborted() const { return m_abort; }
|
||||||
bool is_paused() const { return m_paused; }
|
bool is_paused() const { return m_paused; }
|
||||||
@@ -301,6 +301,7 @@ namespace libtorrent
|
|||||||
session_status status() const;
|
session_status status() const;
|
||||||
void set_peer_id(peer_id const& id);
|
void set_peer_id(peer_id const& id);
|
||||||
void set_key(int key);
|
void set_key(int key);
|
||||||
|
address listen_address() const;
|
||||||
unsigned short listen_port() const;
|
unsigned short listen_port() const;
|
||||||
|
|
||||||
void abort();
|
void abort();
|
||||||
@@ -581,6 +582,11 @@ namespace libtorrent
|
|||||||
struct listen_socket_t
|
struct listen_socket_t
|
||||||
{
|
{
|
||||||
listen_socket_t(): external_port(0) {}
|
listen_socket_t(): external_port(0) {}
|
||||||
|
|
||||||
|
// this is typically empty but can be set
|
||||||
|
// to the WAN IP address of NAT-PMP or UPnP router
|
||||||
|
address external_address;
|
||||||
|
|
||||||
// this is typically set to the same as the local
|
// this is typically set to the same as the local
|
||||||
// listen port. In case a NAT port forward was
|
// listen port. In case a NAT port forward was
|
||||||
// successfully opened, this will be set to the
|
// successfully opened, this will be set to the
|
||||||
|
@@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/deadline_timer.hpp"
|
#include "libtorrent/deadline_timer.hpp"
|
||||||
|
|
||||||
#include <boost/function/function1.hpp>
|
#include <boost/function/function1.hpp>
|
||||||
#include <boost/function/function3.hpp>
|
#include <boost/function/function4.hpp>
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
@@ -50,7 +50,7 @@ namespace libtorrent
|
|||||||
// int: port mapping index
|
// int: port mapping index
|
||||||
// int: external port
|
// int: external port
|
||||||
// std::string: error message
|
// std::string: error message
|
||||||
typedef boost::function<void(int, int, error_code const&)> portmap_callback_t;
|
typedef boost::function<void(int, address, int, error_code const&)> portmap_callback_t;
|
||||||
typedef boost::function<void(char const*)> log_callback_t;
|
typedef boost::function<void(char const*)> log_callback_t;
|
||||||
|
|
||||||
class TORRENT_EXPORT natpmp : public intrusive_ptr_base<natpmp>
|
class TORRENT_EXPORT natpmp : public intrusive_ptr_base<natpmp>
|
||||||
@@ -75,6 +75,7 @@ private:
|
|||||||
|
|
||||||
void update_mapping(int i, mutex::scoped_lock& l);
|
void update_mapping(int i, mutex::scoped_lock& l);
|
||||||
void send_map_request(int i, mutex::scoped_lock& l);
|
void send_map_request(int i, mutex::scoped_lock& l);
|
||||||
|
void send_get_ip_address_request(mutex::scoped_lock& l);
|
||||||
void resend_request(int i, error_code const& e);
|
void resend_request(int i, error_code const& e);
|
||||||
void on_reply(error_code const& e
|
void on_reply(error_code const& e
|
||||||
, std::size_t bytes_transferred);
|
, std::size_t bytes_transferred);
|
||||||
@@ -142,6 +143,9 @@ private:
|
|||||||
// used to receive responses in
|
// used to receive responses in
|
||||||
char m_response_buffer[16];
|
char m_response_buffer[16];
|
||||||
|
|
||||||
|
// router external IP address
|
||||||
|
address m_external_ip;
|
||||||
|
|
||||||
// the endpoint we received the message from
|
// the endpoint we received the message from
|
||||||
udp::endpoint m_remote;
|
udp::endpoint m_remote;
|
||||||
|
|
||||||
|
@@ -251,6 +251,7 @@ namespace libtorrent
|
|||||||
, mixed_mode_algorithm(peer_proportional)
|
, mixed_mode_algorithm(peer_proportional)
|
||||||
, rate_limit_utp(false)
|
, rate_limit_utp(false)
|
||||||
, listen_queue_size(5)
|
, listen_queue_size(5)
|
||||||
|
, announce_double_nat(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// libtorrent version. Used for forward binary compatibility
|
// libtorrent version. Used for forward binary compatibility
|
||||||
@@ -992,6 +993,12 @@ namespace libtorrent
|
|||||||
// the number of connections to accept while we're
|
// the number of connections to accept while we're
|
||||||
// not waiting in an accept() call.
|
// not waiting in an accept() call.
|
||||||
int listen_queue_size;
|
int listen_queue_size;
|
||||||
|
|
||||||
|
// if this is true, the &ip= argument in tracker requests
|
||||||
|
// (unless otherwise specified) will be set to the intermediate
|
||||||
|
// IP address if the user is double NATed. If ther user is not
|
||||||
|
// double NATed, this option does not have an affect
|
||||||
|
bool announce_double_nat;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
@@ -90,12 +90,13 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// int: port-mapping index
|
// int: port-mapping index
|
||||||
|
// address: external address as queried from router
|
||||||
// int: external port
|
// int: external port
|
||||||
// std::string: error message
|
// std::string: error message
|
||||||
// an empty string as error means success
|
// an empty string as error means success
|
||||||
// a port-mapping index of -1 means it's
|
// a port-mapping index of -1 means it's
|
||||||
// an informational log message
|
// an informational log message
|
||||||
typedef boost::function<void(int, int, error_code const&)> portmap_callback_t;
|
typedef boost::function<void(int, address, int, error_code const&)> portmap_callback_t;
|
||||||
typedef boost::function<void(char const*)> log_callback_t;
|
typedef boost::function<void(char const*)> log_callback_t;
|
||||||
|
|
||||||
class TORRENT_EXPORT upnp : public intrusive_ptr_base<upnp>
|
class TORRENT_EXPORT upnp : public intrusive_ptr_base<upnp>
|
||||||
@@ -147,6 +148,9 @@ private:
|
|||||||
void on_upnp_xml(error_code const& e
|
void on_upnp_xml(error_code const& e
|
||||||
, libtorrent::http_parser const& p, rootdevice& d
|
, libtorrent::http_parser const& p, rootdevice& d
|
||||||
, http_connection& c);
|
, http_connection& c);
|
||||||
|
void on_upnp_get_ip_address_response(error_code const& e
|
||||||
|
, libtorrent::http_parser const& p, rootdevice& d
|
||||||
|
, http_connection& c);
|
||||||
void on_upnp_map_response(error_code const& e
|
void on_upnp_map_response(error_code const& e
|
||||||
, libtorrent::http_parser const& p, rootdevice& d
|
, libtorrent::http_parser const& p, rootdevice& d
|
||||||
, int mapping, http_connection& c);
|
, int mapping, http_connection& c);
|
||||||
@@ -159,6 +163,7 @@ private:
|
|||||||
void return_error(int mapping, int code, mutex::scoped_lock& l);
|
void return_error(int mapping, int code, mutex::scoped_lock& l);
|
||||||
void log(char const* msg, mutex::scoped_lock& l);
|
void log(char const* msg, mutex::scoped_lock& l);
|
||||||
|
|
||||||
|
void get_ip_address(rootdevice& d);
|
||||||
void delete_port_mapping(rootdevice& d, int i);
|
void delete_port_mapping(rootdevice& d, int i);
|
||||||
void create_port_mapping(http_connection& c, rootdevice& d, int i);
|
void create_port_mapping(http_connection& c, rootdevice& d, int i);
|
||||||
void post(upnp::rootdevice const& d, char const* soap
|
void post(upnp::rootdevice const& d, char const* soap
|
||||||
@@ -247,6 +252,7 @@ private:
|
|||||||
std::string hostname;
|
std::string hostname;
|
||||||
int port;
|
int port;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
address external_ip;
|
||||||
|
|
||||||
int lease_duration;
|
int lease_duration;
|
||||||
// true if the device supports specifying a
|
// true if the device supports specifying a
|
||||||
|
@@ -59,6 +59,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
|
#include "libtorrent/broadcast_socket.hpp" // for is_local
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
@@ -180,23 +181,34 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (!settings.announce_ip.empty())
|
if (!m_ses.settings().anonymous_mode)
|
||||||
{
|
{
|
||||||
error_code ec;
|
if (!settings.announce_ip.empty())
|
||||||
if (!ec) url += "&ip=" + escape_string(
|
{
|
||||||
settings.announce_ip.c_str(), settings.announce_ip.size());
|
url += "&ip=" + escape_string(
|
||||||
}
|
settings.announce_ip.c_str(), settings.announce_ip.size());
|
||||||
|
}
|
||||||
if (!tracker_req().ipv6.empty() && !i2p)
|
else if (m_ses.settings().announce_double_nat
|
||||||
{
|
&& is_local(m_ses.listen_address()))
|
||||||
url += "&ipv6=";
|
{
|
||||||
url += tracker_req().ipv6;
|
// only use the global external listen address here
|
||||||
}
|
// if it turned out to be on a local network
|
||||||
|
// since otherwise the tracker should use our
|
||||||
if (!tracker_req().ipv4.empty() && !i2p)
|
// source IP to determine our origin
|
||||||
{
|
url += "&ip=" + print_address(m_ses.listen_address());
|
||||||
url += "&ipv4=";
|
}
|
||||||
url += tracker_req().ipv4;
|
|
||||||
|
if (!tracker_req().ipv6.empty() && !i2p)
|
||||||
|
{
|
||||||
|
url += "&ipv6=";
|
||||||
|
url += tracker_req().ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tracker_req().ipv4.empty() && !i2p)
|
||||||
|
{
|
||||||
|
url += "&ipv4=";
|
||||||
|
url += tracker_req().ipv4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -120,6 +120,7 @@ void natpmp::rebind(address const& listen_interface)
|
|||||||
#endif
|
#endif
|
||||||
m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
|
m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
|
||||||
, m_remote, boost::bind(&natpmp::on_reply, self(), _1, _2));
|
, m_remote, boost::bind(&natpmp::on_reply, self(), _1, _2));
|
||||||
|
send_get_ip_address_request(l);
|
||||||
|
|
||||||
for (std::vector<mapping_t>::iterator i = m_mappings.begin()
|
for (std::vector<mapping_t>::iterator i = m_mappings.begin()
|
||||||
, end(m_mappings.end()); i != end; ++i)
|
, end(m_mappings.end()); i != end; ++i)
|
||||||
@@ -132,6 +133,20 @@ void natpmp::rebind(address const& listen_interface)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void natpmp::send_get_ip_address_request(mutex::scoped_lock& l)
|
||||||
|
{
|
||||||
|
using namespace libtorrent::detail;
|
||||||
|
|
||||||
|
char buf[2];
|
||||||
|
char* out = buf;
|
||||||
|
write_uint8(0, out); // NAT-PMP version
|
||||||
|
write_uint8(0, out); // public IP address request opcode
|
||||||
|
log("==> get public IP address", l);
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
m_socket.send_to(asio::buffer(buf, sizeof(buf)), m_nat_endpoint, 0, ec);
|
||||||
|
}
|
||||||
|
|
||||||
bool natpmp::get_mapping(int index, int& local_port, int& external_port, int& protocol) const
|
bool natpmp::get_mapping(int index, int& local_port, int& external_port, int& protocol) const
|
||||||
{
|
{
|
||||||
mutex::scoped_lock l(m_mutex);
|
mutex::scoped_lock l(m_mutex);
|
||||||
@@ -164,7 +179,7 @@ void natpmp::disable(error_code const& ec, mutex::scoped_lock& l)
|
|||||||
i->protocol = none;
|
i->protocol = none;
|
||||||
int index = i - m_mappings.begin();
|
int index = i - m_mappings.begin();
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, 0, ec);
|
m_callback(index, address(), 0, ec);
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
close_impl(l);
|
close_impl(l);
|
||||||
@@ -337,7 +352,7 @@ void natpmp::send_map_request(int i, mutex::scoped_lock& l)
|
|||||||
log(msg, l);
|
log(msg, l);
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint, 0, ec);
|
m_socket.send_to(asio::buffer(buf, sizeof(buf)), m_nat_endpoint, 0, ec);
|
||||||
m.map_sent = true;
|
m.map_sent = true;
|
||||||
m.outstanding_request = true;
|
m.outstanding_request = true;
|
||||||
if (m_abort)
|
if (m_abort)
|
||||||
@@ -428,11 +443,45 @@ void natpmp::on_reply(error_code const& e
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
m_send_timer.cancel(ec);
|
m_send_timer.cancel(ec);
|
||||||
|
|
||||||
|
if (bytes_transferred < 12)
|
||||||
|
{
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "received packet of invalid size: %d", bytes_transferred);
|
||||||
|
log(msg, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char* in = m_response_buffer;
|
char* in = m_response_buffer;
|
||||||
int version = read_uint8(in);
|
int version = read_uint8(in);
|
||||||
int cmd = read_uint8(in);
|
int cmd = read_uint8(in);
|
||||||
int result = read_uint16(in);
|
int result = read_uint16(in);
|
||||||
int time = read_uint32(in);
|
int time = read_uint32(in);
|
||||||
|
|
||||||
|
// for some reason the Airport extreme responds with
|
||||||
|
// a cmd of 130 for the public IP request. However, the
|
||||||
|
// response is still identifiable by its size
|
||||||
|
// this might be a bug triggered by libtorrent not serializing
|
||||||
|
// its port mapping requests and the external IP request
|
||||||
|
if (cmd == 128 || bytes_transferred == 12)
|
||||||
|
{
|
||||||
|
// public IP request response
|
||||||
|
m_external_ip = address_v4(read_uint32(in));
|
||||||
|
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "<== public IP address [ %s ]", print_address(m_external_ip).c_str());
|
||||||
|
log(msg, l);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 16)
|
||||||
|
{
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "received packet of invalid size: %d", bytes_transferred);
|
||||||
|
log(msg, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int private_port = read_uint16(in);
|
int private_port = read_uint16(in);
|
||||||
int public_port = read_uint16(in);
|
int public_port = read_uint16(in);
|
||||||
int lifetime = read_uint32(in);
|
int lifetime = read_uint32(in);
|
||||||
@@ -505,13 +554,14 @@ void natpmp::on_reply(error_code const& e
|
|||||||
|
|
||||||
m->expires = time_now() + hours(2);
|
m->expires = time_now() + hours(2);
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, 0, error_code(ev, get_libtorrent_category()));
|
m_callback(index, address(), 0, error_code(ev, get_libtorrent_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
else if (m->action == mapping_t::action_add)
|
else if (m->action == mapping_t::action_add)
|
||||||
{
|
{
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, m->external_port, error_code(errors::no_error, get_libtorrent_category()));
|
m_callback(index, m_external_ip, m->external_port,
|
||||||
|
error_code(errors::no_error, get_libtorrent_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3608,6 +3608,16 @@ namespace aux {
|
|||||||
return !m_listen_sockets.empty();
|
return !m_listen_sockets.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address session_impl::listen_address() const
|
||||||
|
{
|
||||||
|
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
|
||||||
|
, end(m_listen_sockets.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (i->external_address != address()) return i->external_address;
|
||||||
|
}
|
||||||
|
return address();
|
||||||
|
}
|
||||||
|
|
||||||
unsigned short session_impl::listen_port() const
|
unsigned short session_impl::listen_port() const
|
||||||
{
|
{
|
||||||
// if peer connections are set up to be received over a socks
|
// if peer connections are set up to be received over a socks
|
||||||
@@ -3667,7 +3677,7 @@ namespace aux {
|
|||||||
m_alerts.post_alert(portmap_log_alert(map_transport, msg));
|
m_alerts.post_alert(portmap_log_alert(map_transport, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::on_port_mapping(int mapping, int port
|
void session_impl::on_port_mapping(int mapping, address const& ip, int port
|
||||||
, error_code const& ec, int map_transport)
|
, error_code const& ec, int map_transport)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_network_thread());
|
TORRENT_ASSERT(is_network_thread());
|
||||||
@@ -3685,8 +3695,12 @@ namespace aux {
|
|||||||
|
|
||||||
if (mapping == m_tcp_mapping[map_transport] && port != 0)
|
if (mapping == m_tcp_mapping[map_transport] && port != 0)
|
||||||
{
|
{
|
||||||
if (!m_listen_sockets.empty())
|
if (ip != address()) set_external_address(ip);
|
||||||
|
|
||||||
|
if (!m_listen_sockets.empty()) {
|
||||||
|
m_listen_sockets.front().external_address = ip;
|
||||||
m_listen_sockets.front().external_port = port;
|
m_listen_sockets.front().external_port = port;
|
||||||
|
}
|
||||||
if (m_alerts.should_post<portmap_alert>())
|
if (m_alerts.should_post<portmap_alert>())
|
||||||
m_alerts.post_alert(portmap_alert(mapping, port
|
m_alerts.post_alert(portmap_alert(mapping, port
|
||||||
, map_transport));
|
, map_transport));
|
||||||
@@ -4248,7 +4262,7 @@ namespace aux {
|
|||||||
natpmp* n = new (std::nothrow) natpmp(m_io_service
|
natpmp* n = new (std::nothrow) natpmp(m_io_service
|
||||||
, m_listen_interface.address()
|
, m_listen_interface.address()
|
||||||
, boost::bind(&session_impl::on_port_mapping
|
, boost::bind(&session_impl::on_port_mapping
|
||||||
, this, _1, _2, _3, 0)
|
, this, _1, _2, _3, _4, 0)
|
||||||
, boost::bind(&session_impl::on_port_map_log
|
, boost::bind(&session_impl::on_port_map_log
|
||||||
, this, _1, 0));
|
, this, _1, 0));
|
||||||
if (n == 0) return 0;
|
if (n == 0) return 0;
|
||||||
@@ -4280,7 +4294,7 @@ namespace aux {
|
|||||||
, m_listen_interface.address()
|
, m_listen_interface.address()
|
||||||
, m_settings.user_agent
|
, m_settings.user_agent
|
||||||
, boost::bind(&session_impl::on_port_mapping
|
, boost::bind(&session_impl::on_port_mapping
|
||||||
, this, _1, _2, _3, 1)
|
, this, _1, _2, _3, _4, 1)
|
||||||
, boost::bind(&session_impl::on_port_map_log
|
, boost::bind(&session_impl::on_port_map_log
|
||||||
, this, _1, 1)
|
, this, _1, 1)
|
||||||
, m_settings.upnp_ignore_nonrouters);
|
, m_settings.upnp_ignore_nonrouters);
|
||||||
|
144
src/upnp.cpp
144
src/upnp.cpp
@@ -960,7 +960,42 @@ void upnp::on_upnp_xml(error_code const& e
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_mappings() > 0) update_map(d, 0, l);
|
d.upnp_connection.reset(new http_connection(m_io_service
|
||||||
|
, m_cc, boost::bind(&upnp::on_upnp_get_ip_address_response, self(), _1, _2
|
||||||
|
, boost::ref(d), _5), true
|
||||||
|
, boost::bind(&upnp::get_ip_address, self(), boost::ref(d))));
|
||||||
|
d.upnp_connection->start(d.hostname, to_string(d.port).elems
|
||||||
|
, seconds(10), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void upnp::get_ip_address(rootdevice& d)
|
||||||
|
{
|
||||||
|
mutex::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
|
TORRENT_ASSERT(d.magic == 1337);
|
||||||
|
|
||||||
|
if (!d.upnp_connection)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(d.disabled);
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "getting external IP address");
|
||||||
|
log(msg, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* soap_action = "GetExternalIPAddress";
|
||||||
|
|
||||||
|
char soap[2048];
|
||||||
|
error_code ec;
|
||||||
|
snprintf(soap, sizeof(soap), "<?xml version=\"1.0\"?>\n"
|
||||||
|
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||||
|
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||||
|
"<s:Body><u:%s xmlns:u=\"%s\">"
|
||||||
|
"</u:%s></s:Body></s:Envelope>"
|
||||||
|
, soap_action, d.service_namespace
|
||||||
|
, soap_action);
|
||||||
|
|
||||||
|
post(d, soap, soap_action, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void upnp::disable(error_code const& ec, mutex::scoped_lock& l)
|
void upnp::disable(error_code const& ec, mutex::scoped_lock& l)
|
||||||
@@ -974,7 +1009,7 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l)
|
|||||||
if (i->protocol == none) continue;
|
if (i->protocol == none) continue;
|
||||||
i->protocol = none;
|
i->protocol = none;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(i - m_mappings.begin(), 0, ec);
|
m_callback(i - m_mappings.begin(), address(), 0, ec);
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1012,6 +1047,29 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ip_address_parse_state: public error_code_parse_state
|
||||||
|
{
|
||||||
|
ip_address_parse_state(): in_ip_address(false) {}
|
||||||
|
bool in_ip_address;
|
||||||
|
std::string ip_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
void find_ip_address(int type, char const* string, ip_address_parse_state& state)
|
||||||
|
{
|
||||||
|
find_error_code(type, string, state);
|
||||||
|
if (state.exit) return;
|
||||||
|
|
||||||
|
if (type == xml_start_tag && !std::strcmp("NewExternalIPAddress", string))
|
||||||
|
{
|
||||||
|
state.in_ip_address = true;
|
||||||
|
}
|
||||||
|
else if (type == xml_string && state.in_ip_address)
|
||||||
|
{
|
||||||
|
state.ip_address = string;
|
||||||
|
state.exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct error_code_t
|
struct error_code_t
|
||||||
{
|
{
|
||||||
int code;
|
int code;
|
||||||
@@ -1074,6 +1132,84 @@ namespace libtorrent
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void upnp::on_upnp_get_ip_address_response(error_code const& e
|
||||||
|
, libtorrent::http_parser const& p, rootdevice& d
|
||||||
|
, http_connection& c)
|
||||||
|
{
|
||||||
|
boost::intrusive_ptr<upnp> me(self());
|
||||||
|
|
||||||
|
mutex::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
|
TORRENT_ASSERT(d.magic == 1337);
|
||||||
|
if (d.upnp_connection && d.upnp_connection.get() == &c)
|
||||||
|
{
|
||||||
|
d.upnp_connection->close();
|
||||||
|
d.upnp_connection.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_closing) return;
|
||||||
|
|
||||||
|
if (e && e != asio::error::eof)
|
||||||
|
{
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "error while getting external IP address: %s", e.message().c_str());
|
||||||
|
log(msg, l);
|
||||||
|
if (num_mappings() > 0) update_map(d, 0, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p.header_finished())
|
||||||
|
{
|
||||||
|
log("error while getting external IP address: incomplete http message", l);
|
||||||
|
if (num_mappings() > 0) update_map(d, 0, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.status_code() != 200)
|
||||||
|
{
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "error while getting external IP address: %s", p.message().c_str());
|
||||||
|
log(msg, l);
|
||||||
|
if (num_mappings() > 0) update_map(d, 0, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// response may look like
|
||||||
|
// <?xml version="1.0"?>
|
||||||
|
// <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||||
|
// <s:Body><u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
|
||||||
|
// <NewExternalIPAddress>192.168.160.19</NewExternalIPAddress>
|
||||||
|
// </u:GetExternalIPAddressResponse>
|
||||||
|
// </s:Body>
|
||||||
|
// </s:Envelope>
|
||||||
|
|
||||||
|
char msg[500];
|
||||||
|
snprintf(msg, sizeof(msg), "get external IP address response: %s"
|
||||||
|
, std::string(p.get_body().begin, p.get_body().end).c_str());
|
||||||
|
log(msg, l);
|
||||||
|
|
||||||
|
ip_address_parse_state s;
|
||||||
|
xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
|
||||||
|
, boost::bind(&find_ip_address, _1, _2, boost::ref(s)));
|
||||||
|
if (s.error_code != -1)
|
||||||
|
{
|
||||||
|
char msg[200];
|
||||||
|
snprintf(msg, sizeof(msg), "error while getting external IP address, code: %u"
|
||||||
|
, s.error_code);
|
||||||
|
log(msg, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.ip_address.empty()) {
|
||||||
|
snprintf(msg, sizeof(msg), "got router external IP address %s", s.ip_address.c_str());
|
||||||
|
log(msg, l);
|
||||||
|
d.external_ip = address::from_string(s.ip_address.c_str(), ec);
|
||||||
|
} else {
|
||||||
|
log("failed to find external IP address in response", l);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_mappings() > 0) update_map(d, 0, l);
|
||||||
|
}
|
||||||
|
|
||||||
void upnp::on_upnp_map_response(error_code const& e
|
void upnp::on_upnp_map_response(error_code const& e
|
||||||
, libtorrent::http_parser const& p, rootdevice& d, int mapping
|
, libtorrent::http_parser const& p, rootdevice& d, int mapping
|
||||||
, http_connection& c)
|
, http_connection& c)
|
||||||
@@ -1188,7 +1324,7 @@ void upnp::on_upnp_map_response(error_code const& e
|
|||||||
if (s.error_code == -1)
|
if (s.error_code == -1)
|
||||||
{
|
{
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(mapping, m.external_port, error_code());
|
m_callback(mapping, d.external_ip, m.external_port, error_code());
|
||||||
l.lock();
|
l.lock();
|
||||||
if (d.lease_duration > 0)
|
if (d.lease_duration > 0)
|
||||||
{
|
{
|
||||||
@@ -1231,7 +1367,7 @@ void upnp::return_error(int mapping, int code, mutex::scoped_lock& l)
|
|||||||
error_string += e->msg;
|
error_string += e->msg;
|
||||||
}
|
}
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(mapping, 0, error_code(code, upnp_category));
|
m_callback(mapping, address(), 0, error_code(code, upnp_category));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -193,11 +193,11 @@ struct callback_info
|
|||||||
|
|
||||||
std::list<callback_info> callbacks;
|
std::list<callback_info> callbacks;
|
||||||
|
|
||||||
void callback(int mapping, int port, error_code const& err)
|
void callback(int mapping, address const& ip, int port, error_code const& err)
|
||||||
{
|
{
|
||||||
callback_info info = {mapping, port, err};
|
callback_info info = {mapping, port, err};
|
||||||
callbacks.push_back(info);
|
callbacks.push_back(info);
|
||||||
std::cerr << "mapping: " << mapping << ", port: " << port
|
std::cerr << "mapping: " << mapping << ", port: " << port << ", IP: " << ip
|
||||||
<< ", error: \"" << err.message() << "\"\n";
|
<< ", error: \"" << err.message() << "\"\n";
|
||||||
//TODO: store the callbacks and verify that the ports were successful
|
//TODO: store the callbacks and verify that the ports were successful
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user