From d62b98027829186e52d62ddaed33907fecce1928 Mon Sep 17 00:00:00 2001 From: Andrei Kurushin Date: Sun, 18 Dec 2016 15:31:02 +0300 Subject: [PATCH] backport fix upnp xml_parse --- include/libtorrent/upnp.hpp | 21 ++++++++++ src/upnp.cpp | 82 +++++++++++++++---------------------- test/test_xml.cpp | 52 +++++++++++++++++++++++ 3 files changed, 107 insertions(+), 48 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index beee17768..a5538cded 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -130,9 +130,30 @@ struct parse_state } }; +struct error_code_parse_state +{ + error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {} + bool in_error_code; + bool exit; + int error_code; +}; + +struct ip_address_parse_state: error_code_parse_state +{ + ip_address_parse_state(): in_ip_address(false) {} + bool in_ip_address; + std::string ip_address; +}; + TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string , int str_len, parse_state& state); +TORRENT_EXTRA_EXPORT void find_error_code(int type, char const* string + , int str_len, error_code_parse_state& state); + +TORRENT_EXTRA_EXPORT void find_ip_address(int type, char const* string + , int str_len, ip_address_parse_state& state); + // TODO: support using the windows API for UPnP operations as well class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this { diff --git a/src/upnp.cpp b/src/upnp.cpp index ab10a02a2..f78ac9824 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -1063,53 +1063,39 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l) m_socket.close(); } +void find_error_code(int type, char const* string, int str_len, error_code_parse_state& state) +{ + if (state.exit) return; + if (type == xml_start_tag && !std::strncmp("errorCode", string, size_t(str_len))) + { + state.in_error_code = true; + } + else if (type == xml_string && state.in_error_code) + { + std::string error_code_str(string, str_len); + state.error_code = std::atoi(error_code_str.c_str()); + state.exit = true; + } +} + +void find_ip_address(int type, char const* string, int str_len, ip_address_parse_state& state) +{ + find_error_code(type, string, str_len, state); + if (state.exit) return; + + if (type == xml_start_tag && !std::strncmp("NewExternalIPAddress", string, size_t(str_len))) + { + state.in_ip_address = true; + } + else if (type == xml_string && state.in_ip_address) + { + state.ip_address.assign(string, str_len); + state.exit = true; + } +} + namespace { - struct error_code_parse_state - { - error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {} - bool in_error_code; - bool exit; - int error_code; - }; - - void find_error_code(int type, char const* string, error_code_parse_state& state) - { - if (state.exit) return; - if (type == xml_start_tag && !std::strcmp("errorCode", string)) - { - state.in_error_code = true; - } - else if (type == xml_string && state.in_error_code) - { - state.error_code = std::atoi(string); - state.exit = true; - } - } - - 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 { int code; @@ -1239,7 +1225,7 @@ void upnp::on_upnp_get_ip_address_response(error_code const& e ip_address_parse_state s; xml_parse(const_cast(p.get_body().begin), const_cast(p.get_body().end) - , boost::bind(&find_ip_address, _1, _2, boost::ref(s))); + , boost::bind(&find_ip_address, _1, _2, _3, boost::ref(s))); if (s.error_code != -1) { char msg[500]; @@ -1333,7 +1319,7 @@ void upnp::on_upnp_map_response(error_code const& e error_code_parse_state s; xml_parse(const_cast(p.get_body().begin) , const_cast(p.get_body().end) - , boost::bind(&find_error_code, _1, _2, boost::ref(s))); + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(s))); if (s.error_code != -1) { @@ -1476,7 +1462,7 @@ void upnp::on_upnp_unmap_response(error_code const& e { xml_parse(const_cast(p.get_body().begin) , const_cast(p.get_body().end) - , boost::bind(&find_error_code, _1, _2, boost::ref(s))); + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(s))); } int const proto = m_mappings[mapping].protocol; diff --git a/test/test_xml.cpp b/test/test_xml.cpp index 2ef6df392..a42c38e64 100644 --- a/test/test_xml.cpp +++ b/test/test_xml.cpp @@ -233,6 +233,36 @@ char upnp_xml2[] = "" ""; +char upnp_xml3[] = +"" +"" +"" +"s:Client" +"UPnPError" +"" +"" +"402" +"Invalid Args" +"" +"" +"" +"" +""; + +char upnp_xml4[] = +"" +"" +"" +"" +"123.10.20.30" +"" +"" +""; + using namespace libtorrent; void parser_callback(std::string& out, int token, char const* s, int len @@ -304,6 +334,28 @@ TORRENT_TEST(upnp_parser2) TEST_EQUAL(xml_s.model, "Wireless-G ADSL Home Gateway"); } +TORRENT_TEST(upnp_parser3) +{ + error_code_parse_state xml_s; + xml_parse(upnp_xml3, upnp_xml3 + sizeof(upnp_xml3) + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(xml_s))); + + std::cout << "error_code " << xml_s.error_code << std::endl; + TEST_EQUAL(xml_s.error_code, 402); +} + +TORRENT_TEST(upnp_parser4) +{ + ip_address_parse_state xml_s; + xml_parse(upnp_xml4, upnp_xml4 + sizeof(upnp_xml4) + , boost::bind(&find_ip_address, _1, _2, _3, boost::ref(xml_s))); + + std::cout << "error_code " << xml_s.error_code << std::endl; + std::cout << "ip_address " << xml_s.ip_address << std::endl; + TEST_EQUAL(xml_s.error_code, -1); + TEST_EQUAL(xml_s.ip_address, "123.10.20.30"); +} + TORRENT_TEST(tags) { test_parse("foobar", "BaSfooEbSbarFa");