From e5d1456c584963aaa97f32b86b5647b3b54aa914 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 7 Jan 2008 02:35:29 +0000 Subject: [PATCH] added a failcounter to upnp portmaps --- include/libtorrent/upnp.hpp | 5 +++ src/upnp.cpp | 62 +++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index 1c24455f5..442d7aa4a 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -108,6 +108,7 @@ private: void map_port(rootdevice& d, int i); void unmap_port(rootdevice& d, int i); void disable(); + void return_error(int code); void delete_port_mapping(rootdevice& d, int i); void create_port_mapping(http_connection& c, rootdevice& d, int i); @@ -121,6 +122,7 @@ private: , local_port(0) , external_port(0) , protocol(1) + , failcount(0) {} // the time the port mapping will expire @@ -139,6 +141,9 @@ private: // 1 = udp, 0 = tcp int protocol; + + // the number of times this mapping has failed + int failcount; }; struct rootdevice diff --git a/src/upnp.cpp b/src/upnp.cpp index 6ff3a35e9..064b6550d 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -471,6 +471,13 @@ void upnp::map_port(rootdevice& d, int i) TORRENT_ASSERT(d.magic == 1337); if (d.upnp_connection) return; + if (d.mapping[i].failcount > 5) + { + // giving up + if (i < num_mappings - 1) + map_port(d, i + 1); + return; + } if (!d.mapping[i].need_update) { #ifdef TORRENT_UPNP_LOGGING @@ -825,32 +832,37 @@ void upnp::on_upnp_map_response(asio::error_code const& e // only permanent leases supported d.lease_duration = 0; d.mapping[mapping].need_update = true; + ++d.mapping[mapping].failcount; map_port(d, mapping); return; } - else if (s.error_code == 718) + else if (s.error_code == 718 || s.error_code == 727) { - // conflict in mapping, try next external port - ++d.mapping[mapping].external_port; + if (d.mapping[mapping].external_port != 0) + { + // conflict in mapping, set port to wildcard + // and let the router decide + d.mapping[mapping].external_port = 0; + d.mapping[mapping].need_update = true; + ++d.mapping[mapping].failcount; + map_port(d, mapping); + return; + } + return_error(s.error_code); + } + else if (s.error_code == 716) + { + // The external port cannot be wildcarder + // pick a random port + d.mapping[mapping].external_port = 40000 + (rand() % 10000); d.mapping[mapping].need_update = true; + ++d.mapping[mapping].failcount; map_port(d, mapping); return; } else if (s.error_code != -1) { - int num_errors = sizeof(error_codes) / sizeof(error_codes[0]); - error_code_t* end = error_codes + num_errors; - error_code_t tmp = {s.error_code, 0}; - error_code_t* e = std::lower_bound(error_codes, end, tmp - , bind(&error_code_t::code, _1) < bind(&error_code_t::code, _2)); - std::string error_string = "UPnP mapping error "; - error_string += boost::lexical_cast(s.error_code); - if (e != end && e->code == s.error_code) - { - error_string += ": "; - error_string += e->msg; - } - m_callback(0, 0, error_string); + return_error(s.error_code); } #ifdef TORRENT_UPNP_LOGGING @@ -887,6 +899,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e { d.mapping[mapping].expires = max_time(); } + d.mapping[mapping].failcount = 0; } for (int i = 0; i < num_mappings; ++i) @@ -899,6 +912,23 @@ void upnp::on_upnp_map_response(asio::error_code const& e } } +void upnp::return_error(int code) +{ + int num_errors = sizeof(error_codes) / sizeof(error_codes[0]); + error_code_t* end = error_codes + num_errors; + error_code_t tmp = {code, 0}; + error_code_t* e = std::lower_bound(error_codes, end, tmp + , bind(&error_code_t::code, _1) < bind(&error_code_t::code, _2)); + std::string error_string = "UPnP mapping error "; + error_string += boost::lexical_cast(code); + if (e != end && e->code == code) + { + error_string += ": "; + error_string += e->msg; + } + m_callback(0, 0, error_string); +} + void upnp::on_upnp_unmap_response(asio::error_code const& e , libtorrent::http_parser const& p, rootdevice& d, int mapping) {