From dfccb5703c4d85ab1a54429016b103101bdc54ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Wed, 28 Sep 2011 22:01:57 +0200 Subject: File Transfer refactoring. NAT traversal classes refactoring. Added beginnings of a NetworkTool. diff --git a/.cproject b/.cproject index 7971420..dc35a7d 100644 --- a/.cproject +++ b/.cproject @@ -3199,6 +3199,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project index fcdfcdc..60b9ebf 100644 --- a/.project +++ b/.project @@ -18,7 +18,7 @@ org.eclipse.cdt.make.core.autoBuildTarget - + Swift org.eclipse.cdt.make.core.buildArguments @@ -29,6 +29,10 @@ python + org.eclipse.cdt.make.core.buildLocation + + + org.eclipse.cdt.make.core.cleanBuildTarget -c @@ -50,7 +54,7 @@ org.eclipse.cdt.make.core.fullBuildTarget - + Swift org.eclipse.cdt.make.core.stopOnError diff --git a/3rdParty/Boost/src/boost/logic/tribool.hpp b/3rdParty/Boost/src/boost/logic/tribool.hpp new file mode 100644 index 0000000..229feb4 --- /dev/null +++ b/3rdParty/Boost/src/boost/logic/tribool.hpp @@ -0,0 +1,460 @@ +// Three-state boolean logic library + +// Copyright Douglas Gregor 2002-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// For more information, see http://www.boost.org +#ifndef BOOST_LOGIC_TRIBOOL_HPP +#define BOOST_LOGIC_TRIBOOL_HPP + +#include +#include +#include + +#if BOOST_WORKAROUND(_MSC_VER, >= 1200) +# pragma once +#endif + +namespace boost { namespace logic { + +/// INTERNAL ONLY +namespace detail { +/** + * INTERNAL ONLY + * + * \brief A type used only to uniquely identify the 'indeterminate' + * function/keyword. + */ +struct indeterminate_t +{ +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0600) + char dummy_; // BCB would use 8 bytes by default +#endif +}; + +} // end namespace detail + +/** + * INTERNAL ONLY + * The type of the 'indeterminate' keyword. This has the same type as the + * function 'indeterminate' so that we can recognize when the keyword is + * used. + */ +typedef bool (*indeterminate_keyword_t)(tribool, detail::indeterminate_t); + +/** + * \brief Keyword and test function for the indeterminate tribool value + * + * The \c indeterminate function has a dual role. It's first role is + * as a unary function that tells whether the tribool value is in the + * "indeterminate" state. It's second role is as a keyword + * representing the indeterminate (just like "true" and "false" + * represent the true and false states). If you do not like the name + * "indeterminate", and would prefer to use a different name, see the + * macro \c BOOST_TRIBOOL_THIRD_STATE. + * + * \returns x.value == tribool::indeterminate_value + * \throws nothrow + */ +inline bool +indeterminate(tribool x, + detail::indeterminate_t dummy = detail::indeterminate_t()); + +/** + * \brief A 3-state boolean type. + * + * 3-state boolean values are either true, false, or + * indeterminate. + */ +class tribool +{ +private: + /// INTERNAL ONLY + struct dummy { + void nonnull() {}; + }; + + typedef void (dummy::*safe_bool)(); + +public: + /** + * Construct a new 3-state boolean value with the value 'false'. + * + * \throws nothrow + */ + tribool() : value(false_value) {} + + /** + * Construct a new 3-state boolean value with the given boolean + * value, which may be \c true or \c false. + * + * \throws nothrow + */ + tribool(bool value) : value(value? true_value : false_value) {} + + /** + * Construct a new 3-state boolean value with an indeterminate value. + * + * \throws nothrow + */ + tribool(indeterminate_keyword_t) : value(indeterminate_value) {} + + /** + * Use a 3-state boolean in a boolean context. Will evaluate true in a + * boolean context only when the 3-state boolean is definitely true. + * + * \returns true if the 3-state boolean is true, false otherwise + * \throws nothrow + */ + operator safe_bool() const + { + return value == true_value? &dummy::nonnull : 0; + } + + /** + * The actual stored value in this 3-state boolean, which may be false, true, + * or indeterminate. + */ + enum value_t { false_value, true_value, indeterminate_value } value; +}; + +// Check if the given tribool has an indeterminate value. Also doubles as a +// keyword for the 'indeterminate' value +inline bool indeterminate(tribool x, detail::indeterminate_t) +{ + return x.value == tribool::indeterminate_value; +} + +/** @defgroup logical Logical operations + */ +//@{ +/** + * \brief Computes the logical negation of a tribool + * + * \returns the logical negation of the tribool, according to the + * table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
!
+ *
false
true
true
false
indeterminate
indeterminate
+ * \throws nothrow + */ +inline tribool operator!(tribool x) +{ + return x.value == tribool::false_value? tribool(true) + :x.value == tribool::true_value? tribool(false) + :tribool(indeterminate); +} + +/** + * \brief Computes the logical conjuction of two tribools + * + * \returns the result of logically ANDing the two tribool values, + * according to the following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
&&
false
true
indeterminate
false
false
false
false
true
false
true
indeterminate
indeterminate
false
indeterminate
indeterminate
+ * \throws nothrow + */ +inline tribool operator&&(tribool x, tribool y) +{ + if (static_cast(!x) || static_cast(!y)) + return false; + else if (static_cast(x) && static_cast(y)) + return true; + else + return indeterminate; +} + +/** + * \overload + */ +inline tribool operator&&(tribool x, bool y) +{ return y? x : tribool(false); } + +/** + * \overload + */ +inline tribool operator&&(bool x, tribool y) +{ return x? y : tribool(false); } + +/** + * \overload + */ +inline tribool operator&&(indeterminate_keyword_t, tribool x) +{ return !x? tribool(false) : tribool(indeterminate); } + +/** + * \overload + */ +inline tribool operator&&(tribool x, indeterminate_keyword_t) +{ return !x? tribool(false) : tribool(indeterminate); } + +/** + * \brief Computes the logical disjunction of two tribools + * + * \returns the result of logically ORing the two tribool values, + * according to the following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
||
false
true
indeterminate
false
false
true
indeterminate
true
true
true
true
indeterminate
indeterminate
true
indeterminate
+ * \throws nothrow + */ +inline tribool operator||(tribool x, tribool y) +{ + if (static_cast(!x) && static_cast(!y)) + return false; + else if (static_cast(x) || static_cast(y)) + return true; + else + return indeterminate; +} + +/** + * \overload + */ +inline tribool operator||(tribool x, bool y) +{ return y? tribool(true) : x; } + +/** + * \overload + */ +inline tribool operator||(bool x, tribool y) +{ return x? tribool(true) : y; } + +/** + * \overload + */ +inline tribool operator||(indeterminate_keyword_t, tribool x) +{ return x? tribool(true) : tribool(indeterminate); } + +/** + * \overload + */ +inline tribool operator||(tribool x, indeterminate_keyword_t) +{ return x? tribool(true) : tribool(indeterminate); } +//@} + +/** + * \brief Compare tribools for equality + * + * \returns the result of comparing two tribool values, according to + * the following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
==
false
true
indeterminate
false
true
false
indeterminate
true
false
true
indeterminate
indeterminate
indeterminate
indeterminate
indeterminate
+ * \throws nothrow + */ +inline tribool operator==(tribool x, tribool y) +{ + if (indeterminate(x) || indeterminate(y)) + return indeterminate; + else + return (x && y) || (!x && !y); +} + +/** + * \overload + */ +inline tribool operator==(tribool x, bool y) { return x == tribool(y); } + +/** + * \overload + */ +inline tribool operator==(bool x, tribool y) { return tribool(x) == y; } + +/** + * \overload + */ +inline tribool operator==(indeterminate_keyword_t, tribool x) +{ return tribool(indeterminate) == x; } + +/** + * \overload + */ +inline tribool operator==(tribool x, indeterminate_keyword_t) +{ return tribool(indeterminate) == x; } + +/** + * \brief Compare tribools for inequality + * + * \returns the result of comparing two tribool values for inequality, + * according to the following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
!=
false
true
indeterminate
false
false
true
indeterminate
true
true
false
indeterminate
indeterminate
indeterminate
indeterminate
indeterminate
+ * \throws nothrow + */ +inline tribool operator!=(tribool x, tribool y) +{ + if (indeterminate(x) || indeterminate(y)) + return indeterminate; + else + return !((x && y) || (!x && !y)); +} + +/** + * \overload + */ +inline tribool operator!=(tribool x, bool y) { return x != tribool(y); } + +/** + * \overload + */ +inline tribool operator!=(bool x, tribool y) { return tribool(x) != y; } + +/** + * \overload + */ +inline tribool operator!=(indeterminate_keyword_t, tribool x) +{ return tribool(indeterminate) != x; } + +/** + * \overload + */ +inline tribool operator!=(tribool x, indeterminate_keyword_t) +{ return x != tribool(indeterminate); } + +} } // end namespace boost::logic + +// Pull tribool and indeterminate into namespace "boost" +namespace boost { + using logic::tribool; + using logic::indeterminate; +} + +/** + * \brief Declare a new name for the third state of a tribool + * + * Use this macro to declare a new name for the third state of a + * tribool. This state can have any number of new names (in addition + * to \c indeterminate), all of which will be equivalent. The new name will be + * placed in the namespace in which the macro is expanded. + * + * Example: + * BOOST_TRIBOOL_THIRD_STATE(true_or_false) + * + * tribool x(true_or_false); + * // potentially set x + * if (true_or_false(x)) { + * // don't know what x is + * } + */ +#define BOOST_TRIBOOL_THIRD_STATE(Name) \ +inline bool \ +Name(boost::logic::tribool x, \ + boost::logic::detail::indeterminate_t dummy = \ + boost::logic::detail::indeterminate_t()) \ +{ return x.value == boost::logic::tribool::indeterminate_value; } + +#endif // BOOST_LOGIC_TRIBOOL_HPP + diff --git a/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp b/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp new file mode 100644 index 0000000..2cdd91b --- /dev/null +++ b/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp @@ -0,0 +1,15 @@ +// Three-state boolean logic library + +// Copyright Douglas Gregor 2002-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// For more information, see http://www.boost.org +#ifndef BOOST_LOGIC_TRIBOOL_FWD_HPP +#define BOOST_LOGIC_TRIBOOL_FWD_HPP + +namespace boost { namespace logic { class tribool; } } + +#endif // BOOST_LOGIC_TRIBOOL_FWD_HPP diff --git a/3rdParty/Boost/update.sh b/3rdParty/Boost/update.sh index c272d1a..a7c0638 100755 --- a/3rdParty/Boost/update.sh +++ b/3rdParty/Boost/update.sh @@ -32,9 +32,10 @@ fi uuid/uuid_generators.hpp \ variant.hpp \ regex.hpp \ - boost/unordered_map.hpp \ - boost/algorithm/string.hpp \ - boost/format.hpp \ + unordered_map.hpp \ + algorithm/string.hpp \ + format.hpp \ + logic/tribool.hpp \ assign/list_of.hpp \ $TARGET_DIR diff --git a/Swiften/Examples/NetworkTool/.gitignore b/Swiften/Examples/NetworkTool/.gitignore new file mode 100644 index 0000000..ab9c4e7 --- /dev/null +++ b/Swiften/Examples/NetworkTool/.gitignore @@ -0,0 +1 @@ +NetworkTool diff --git a/Swiften/Examples/NetworkTool/SConscript b/Swiften/Examples/NetworkTool/SConscript new file mode 100644 index 0000000..0b27f0d --- /dev/null +++ b/Swiften/Examples/NetworkTool/SConscript @@ -0,0 +1,9 @@ +Import("env") + +myenv = env.Clone() +myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + +linkLocalTool = myenv.Program("NetworkTool", [ + "main.cpp" + ]) diff --git a/Swiften/Examples/NetworkTool/main.cpp b/Swiften/Examples/NetworkTool/main.cpp new file mode 100644 index 0000000..fa19e14 --- /dev/null +++ b/Swiften/Examples/NetworkTool/main.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include +#include + +#include +#include +#include +#include +#include + +using namespace Swift; + +SimpleEventLoop eventLoop; + +void handleGetPublicIPRequestResponse(const boost::optional& result) { + if (result) { + std::cerr << "Result: " << result->toString() << std::endl;; + } + else { + std::cerr << "No result" << std::endl; + } + eventLoop.stop(); +} + +void handleGetForwardPortRequestResponse(const boost::optional& result) { + if (result) { + std::cerr << "Result: " << result->publicPort << " -> " << result->localPort << std::endl;; + } + else { + std::cerr << "No result" << std::endl; + } + eventLoop.stop(); +} + +void handleRemovePortForwardingRequestResponse(bool result) { + if (result) { + std::cerr << "Result: OK" << std::endl; + } + else { + std::cerr << "Result: ERROR" << std::endl; + } + eventLoop.stop(); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "Invalid parameters" << std::endl; + return -1; + } + + PlatformNATTraversalWorker natTraverser(&eventLoop); + if (std::string(argv[1]) == "get-public-ip") { + boost::shared_ptr query = natTraverser.createGetPublicIPRequest(); + query->onResult.connect(boost::bind(&handleGetPublicIPRequestResponse, _1)); + query->run(); + eventLoop.run(); + } + else if (std::string(argv[1]) == "add-port-forward") { + if (argc < 4) { + std::cerr << "Invalid parameters" << std::endl; + } + boost::shared_ptr query = natTraverser.createForwardPortRequest(boost::lexical_cast(argv[2]), boost::lexical_cast(argv[3])); + query->onResult.connect(boost::bind(&handleGetForwardPortRequestResponse, _1)); + query->run(); + eventLoop.run(); + } + else if (std::string(argv[1]) == "remove-port-forward") { + if (argc < 4) { + std::cerr << "Invalid parameters" << std::endl; + } + boost::shared_ptr query = natTraverser.createRemovePortForwardingRequest(boost::lexical_cast(argv[2]), boost::lexical_cast(argv[3])); + query->onResult.connect(boost::bind(&handleRemovePortForwardingRequestResponse, _1)); + query->run(); + eventLoop.run(); + } +} diff --git a/Swiften/Examples/SConscript b/Swiften/Examples/SConscript index 9b9a35a..fb568fc 100644 --- a/Swiften/Examples/SConscript +++ b/Swiften/Examples/SConscript @@ -7,6 +7,7 @@ SConscript(dirs = [ "SendFile", "ConnectivityTest", "LinkLocalTool", + "NetworkTool", "ParserTester", "BenchTool", ]) diff --git a/Swiften/FileTransfer/ConnectivityManager.cpp b/Swiften/FileTransfer/ConnectivityManager.cpp index 1002b45..7d25991 100644 --- a/Swiften/FileTransfer/ConnectivityManager.cpp +++ b/Swiften/FileTransfer/ConnectivityManager.cpp @@ -92,7 +92,7 @@ void ConnectivityManager::natTraversalGetPublicIPResult(boost::optional mapping) { +void ConnectivityManager::natTraversalForwardPortResult(boost::optional mapping) { if (mapping) { SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; } else { diff --git a/Swiften/FileTransfer/ConnectivityManager.h b/Swiften/FileTransfer/ConnectivityManager.h index 41e0ab6..c094c02 100644 --- a/Swiften/FileTransfer/ConnectivityManager.h +++ b/Swiften/FileTransfer/ConnectivityManager.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace Swift { @@ -32,7 +33,7 @@ public: private: void natTraversalGetPublicIPResult(boost::optional address); - void natTraversalForwardPortResult(boost::optional mapping); + void natTraversalForwardPortResult(boost::optional mapping); private: NATTraverser* natTraversalWorker; diff --git a/Swiften/Network/MiniUPnPInterface.cpp b/Swiften/Network/MiniUPnPInterface.cpp new file mode 100644 index 0000000..f6e3b5d --- /dev/null +++ b/Swiften/Network/MiniUPnPInterface.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include +#include +#include + +#include + +namespace Swift { + +MiniUPnPInterface::MiniUPnPInterface() : isValid(false) { + int error = 0; + deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); + if (!deviceList) { + return; + } + + char lanAddress[64]; + if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddress, sizeof(lanAddress))) { + return; + } + localAddress = std::string(lanAddress); + isValid = true; +} + +MiniUPnPInterface::~MiniUPnPInterface() { + if (isValid) { + FreeUPNPUrls(&urls); + } + freeUPNPDevlist(deviceList); +} + +boost::optional MiniUPnPInterface::getPublicIP() { + if (!isValid) { + return boost::optional(); + } + char externalIPAddress[40]; + int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + if (ret != UPNPCOMMAND_SUCCESS) { + return boost::optional(); + } + else { + return HostAddress(std::string(externalIPAddress)); + } +} + +boost::optional MiniUPnPInterface::addPortForward(int actualLocalPort, int actualPublicPort) { + if (!isValid) { + return boost::optional(); + } + + NATPortMapping mapping(actualLocalPort, actualPublicPort, NATPortMapping::TCP); + + std::string publicPort = boost::lexical_cast(mapping.publicPort); + std::string localPort = boost::lexical_cast(mapping.localPort); + std::string leaseSeconds = boost::lexical_cast(mapping.leaseInSeconds); + + int ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), localPort.c_str(), localAddress.c_str(), 0, mapping.protocol == NATPortMapping::TCP ? "TCP" : "UDP", 0, leaseSeconds.c_str()); + if (ret == UPNPCOMMAND_SUCCESS) { + return mapping; + } + else { + return boost::optional(); + } +} + +bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { + if (!isValid) { + return false; + } + + std::string publicPort = boost::lexical_cast(mapping.publicPort); + std::string localPort = boost::lexical_cast(mapping.localPort); + std::string leaseSeconds = boost::lexical_cast(mapping.leaseInSeconds); + + int ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), mapping.protocol == NATPortMapping::TCP ? "TCP" : "UDP", 0); + return ret == UPNPCOMMAND_SUCCESS; +} + +} diff --git a/Swiften/Network/MiniUPnPInterface.h b/Swiften/Network/MiniUPnPInterface.h new file mode 100644 index 0000000..ae9be66 --- /dev/null +++ b/Swiften/Network/MiniUPnPInterface.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace Swift { + class MiniUPnPInterface : public NATTraversalInterface { + public: + MiniUPnPInterface(); + ~MiniUPnPInterface(); + + virtual bool isAvailable() { + return isValid; + } + + boost::optional getPublicIP(); + boost::optional addPortForward(int localPort, int publicPort); + bool removePortForward(const NATPortMapping&); + + private: + bool isValid; + std::string localAddress; + UPNPDev* deviceList; + UPNPUrls urls; + IGDdatas data; + }; +} diff --git a/Swiften/Network/NATPMPInterface.cpp b/Swiften/Network/NATPMPInterface.cpp new file mode 100644 index 0000000..74f582c --- /dev/null +++ b/Swiften/Network/NATPMPInterface.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + + +namespace Swift { + +NATPMPInterface::NATPMPInterface() { + initnatpmp(&natpmp, 0, 0); +} + +NATPMPInterface::~NATPMPInterface() { + closenatpmp(&natpmp); +} + +bool NATPMPInterface::isAvailable() { + return getPublicIP(); +} + +boost::optional NATPMPInterface::getPublicIP() { + if (sendpublicaddressrequest(&natpmp) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; + return boost::optional(); + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while (r == NATPMP_TRYAGAIN); + + if (r == 0) { + return boost::optional(HostAddress(reinterpret_cast(&(response.pnu.publicaddress.addr)), 4)); + } + else { + SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; + return boost::optional(); + } +} + +boost::optional NATPMPInterface::addPortForward(int localPort, int publicPort) { + NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); + if (sendnewportmappingrequest(&natpmp, mapping.protocol == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.leaseInSeconds, mapping.publicPort, mapping.localPort) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; + return boost::optional(); + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while(r == NATPMP_TRYAGAIN); + + if (r == 0) { + mapping.localPort = response.pnu.newportmapping.privateport; + mapping.publicPort = response.pnu.newportmapping.mappedpublicport; + mapping.leaseInSeconds = response.pnu.newportmapping.lifetime; + return mapping; + } + else { + SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + return boost::optional(); + } +} + +bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { + if (sendnewportmappingrequest(&natpmp, mapping.protocol == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.localPort) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; + return false; + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while(r == NATPMP_TRYAGAIN); + + if (r == 0) { + return true; + } + else { + SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + return false; + } +} + + +} diff --git a/Swiften/Network/NATPMPInterface.h b/Swiften/Network/NATPMPInterface.h new file mode 100644 index 0000000..55f5b87 --- /dev/null +++ b/Swiften/Network/NATPMPInterface.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace Swift { + class NATPMPInterface : public NATTraversalInterface { + public: + NATPMPInterface(); + ~NATPMPInterface(); + + virtual bool isAvailable(); + + virtual boost::optional getPublicIP(); + virtual boost::optional addPortForward(int localPort, int publicPort); + virtual bool removePortForward(const NATPortMapping&); + + private: + natpmp_t natpmp; + }; +} diff --git a/Swiften/Network/NATPMPNATTraversalForwardPortRequest.cpp b/Swiften/Network/NATPMPNATTraversalForwardPortRequest.cpp deleted file mode 100644 index d7ef88a..0000000 --- a/Swiften/Network/NATPMPNATTraversalForwardPortRequest.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "NATPMPNATTraversalForwardPortRequest.h" - -#include - -#include - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -namespace Swift { - -NATPMPNATTraversalForwardPortRequest::NATPMPNATTraversalForwardPortRequest(NATTraversalForwardPortRequest::PortMapping mapping, PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker), mapping(mapping) { - -} - -NATPMPNATTraversalForwardPortRequest::~NATPMPNATTraversalForwardPortRequest() { - -} - -void NATPMPNATTraversalForwardPortRequest::runBlocking() { - boost::optional result; - - natpmp_t natpmp; - natpmpresp_t response; - initnatpmp(&natpmp, 0, 0); - - do { - if (sendnewportmappingrequest(&natpmp, mapping.protocol == PortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.leaseInSeconds, mapping.publicPort, mapping.localPort) != 2) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; - break; - } - int r = 0; - - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - } while(r == NATPMP_TRYAGAIN); - - if (r == 0) { - if (response.pnu.newportmapping.privateport == mapping.localPort && - response.pnu.newportmapping.mappedpublicport == mapping.publicPort) { - mapping.leaseInSeconds = response.pnu.newportmapping.lifetime; - result = boost::optional(mapping); - } - } else { - SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; - } - } while(false); - closenatpmp(&natpmp); - - onResult(result); -} - -} diff --git a/Swiften/Network/NATPMPNATTraversalForwardPortRequest.h b/Swiften/Network/NATPMPNATTraversalForwardPortRequest.h deleted file mode 100644 index 99a5d04..0000000 --- a/Swiften/Network/NATPMPNATTraversalForwardPortRequest.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class NATPMPNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { -public: - NATPMPNATTraversalForwardPortRequest(NATTraversalForwardPortRequest::PortMapping, PlatformNATTraversalWorker*); - virtual ~NATPMPNATTraversalForwardPortRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } - -private: - NATTraversalForwardPortRequest::PortMapping mapping; -}; - -} diff --git a/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.cpp b/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.cpp deleted file mode 100644 index 0f6067d..0000000 --- a/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "NATPMPNATTraversalGetPublicIPRequest.h" - -#include - -#include - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -namespace Swift { - -NATPMPNATTraversalGetPublicIPRequest::NATPMPNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker) { - -} - -NATPMPNATTraversalGetPublicIPRequest::~NATPMPNATTraversalGetPublicIPRequest() { - -} - -/* -TODO: a non-blocking solution should be possible too here -void NATPMPNATTraversalGetPublicIPRequest::run() { - // we can run directly since libnatpmp's API is asynchronous - runBlocking(); -}*/ - -void NATPMPNATTraversalGetPublicIPRequest::runBlocking() { - boost::optional result; - - natpmp_t natpmp; - natpmpresp_t response; - initnatpmp(&natpmp, 0, 0); - - do { - if (sendpublicaddressrequest(&natpmp) != 2) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; - break; - } - int r = 0; - - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - } while(r == NATPMP_TRYAGAIN); - - if (r == 0) { - result = boost::optional(HostAddress(reinterpret_cast(&(response.pnu.publicaddress.addr)), 4)); - } else { - SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; - } - } while(false); - closenatpmp(&natpmp); - onResult(result); -} - -} diff --git a/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.h b/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.h deleted file mode 100644 index dba447c..0000000 --- a/Swiften/Network/NATPMPNATTraversalGetPublicIPRequest.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class NATPMPNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest, public PlatformNATTraversalRequest { -public: - NATPMPNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker*); - virtual ~NATPMPNATTraversalGetPublicIPRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } -}; - -} diff --git a/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.cpp b/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.cpp deleted file mode 100644 index 8ba20a6..0000000 --- a/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "NATPMPNATTraversalRemovePortForwardingRequest.h" - -#include - -#include - -#include -#include -#include -#include - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -namespace Swift { - -NATPMPNATTraversalRemovePortForwardingRequest::NATPMPNATTraversalRemovePortForwardingRequest(PortMapping mapping, PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker), mapping(mapping) { - -} - -NATPMPNATTraversalRemovePortForwardingRequest::~NATPMPNATTraversalRemovePortForwardingRequest() { - -} - -void NATPMPNATTraversalRemovePortForwardingRequest::runBlocking() { - boost::optional result; - - natpmp_t natpmp; - natpmpresp_t response; - initnatpmp(&natpmp, 0, 0); - - do { - if (sendnewportmappingrequest(&natpmp, mapping.protocol == PortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.localPort) != 2) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; - break; - } - int r = 0; - - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - } while(r == NATPMP_TRYAGAIN); - - if (r == 0) { - if (response.pnu.newportmapping.privateport == mapping.localPort && - response.pnu.newportmapping.mappedpublicport == mapping.publicPort) { - mapping.leaseInSeconds = response.pnu.newportmapping.lifetime; - result = boost::optional(true); - } - } else { - result = boost::optional(false); - SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; - } - } while(false); - closenatpmp(&natpmp); - - onResult(result); -} - -} diff --git a/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.h b/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.h deleted file mode 100644 index aefbdc0..0000000 --- a/Swiften/Network/NATPMPNATTraversalRemovePortForwardingRequest.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class NATPMPNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { -public: - NATPMPNATTraversalRemovePortForwardingRequest(PortMapping, PlatformNATTraversalWorker*); - virtual ~NATPMPNATTraversalRemovePortForwardingRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } - -private: - PortMapping mapping; -}; - -} diff --git a/Swiften/Network/NATPortMapping.h b/Swiften/Network/NATPortMapping.h new file mode 100644 index 0000000..82f62bb --- /dev/null +++ b/Swiften/Network/NATPortMapping.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +namespace Swift { + struct NATPortMapping { + enum Protocol { + TCP, + UDP, + }; + + NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { + + } + + int publicPort; + int localPort; + Protocol protocol; + int leaseInSeconds; + }; +} diff --git a/Swiften/Network/NATTraversalForwardPortRequest.h b/Swiften/Network/NATTraversalForwardPortRequest.h index 8cdbd3d..1bbc9ca 100644 --- a/Swiften/Network/NATTraversalForwardPortRequest.h +++ b/Swiften/Network/NATTraversalForwardPortRequest.h @@ -7,28 +7,16 @@ #pragma once #include -#include + +#include namespace Swift { class NATTraversalForwardPortRequest { public: - struct PortMapping { - enum Protocol { - TCP, - UDP, - }; - - unsigned int publicPort; - unsigned int localPort; - Protocol protocol; - unsigned long leaseInSeconds; - }; - - public: virtual ~NATTraversalForwardPortRequest(); virtual void run() = 0; - boost::signal)> onResult; + boost::signal)> onResult; }; } diff --git a/Swiften/Network/NATTraversalInterface.cpp b/Swiften/Network/NATTraversalInterface.cpp new file mode 100644 index 0000000..f8a0cc2 --- /dev/null +++ b/Swiften/Network/NATTraversalInterface.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + + +namespace Swift { + +NATTraversalInterface::~NATTraversalInterface() { +} + +} diff --git a/Swiften/Network/NATTraversalInterface.h b/Swiften/Network/NATTraversalInterface.h new file mode 100644 index 0000000..428db10 --- /dev/null +++ b/Swiften/Network/NATTraversalInterface.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include + +namespace Swift { + class NATTraversalInterface { + public: + virtual ~NATTraversalInterface(); + + virtual bool isAvailable() = 0; + + virtual boost::optional getPublicIP() = 0; + virtual boost::optional addPortForward(int localPort, int publicPort) = 0; + virtual bool removePortForward(const NATPortMapping&) = 0; + }; +} diff --git a/Swiften/Network/NATTraverser.h b/Swiften/Network/NATTraverser.h index 4afd624..e48ce26 100644 --- a/Swiften/Network/NATTraverser.h +++ b/Swiften/Network/NATTraverser.h @@ -18,7 +18,7 @@ namespace Swift { virtual ~NATTraverser(); virtual boost::shared_ptr createGetPublicIPRequest() = 0; - virtual boost::shared_ptr createForwardPortRequest(unsigned int localPort, unsigned int publicPort) = 0; - virtual boost::shared_ptr createRemovePortForwardingRequest(unsigned int localPort, unsigned int publicPort) = 0; + virtual boost::shared_ptr createForwardPortRequest(int localPort, int publicPort) = 0; + virtual boost::shared_ptr createRemovePortForwardingRequest(int localPort, int publicPort) = 0; }; } diff --git a/Swiften/Network/NullNATTraversalInterface.h b/Swiften/Network/NullNATTraversalInterface.h new file mode 100644 index 0000000..c76634f --- /dev/null +++ b/Swiften/Network/NullNATTraversalInterface.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include + +namespace Swift { + class NullNATTraversalInterface : public NATTraversalInterface { + public: + virtual bool isAvailable() { + return true; + } + + virtual boost::optional getPublicIP() { + return boost::optional(); + } + + virtual boost::optional addPortForward(int, int) { + return boost::optional(); + } + + virtual bool removePortForward(const NATPortMapping&) { + return false; + } + }; +} diff --git a/Swiften/Network/NullNATTraverser.cpp b/Swiften/Network/NullNATTraverser.cpp index 018ef91..8cb35cd 100644 --- a/Swiften/Network/NullNATTraverser.cpp +++ b/Swiften/Network/NullNATTraverser.cpp @@ -35,7 +35,7 @@ class NullNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest } virtual void run() { - eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional())); + eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional())); } private: @@ -62,11 +62,11 @@ boost::shared_ptr NullNATTraverser::createGetPub return boost::make_shared(eventLoop); } -boost::shared_ptr NullNATTraverser::createForwardPortRequest(unsigned int, unsigned int) { +boost::shared_ptr NullNATTraverser::createForwardPortRequest(int, int) { return boost::make_shared(eventLoop); } -boost::shared_ptr NullNATTraverser::createRemovePortForwardingRequest(unsigned int, unsigned int) { +boost::shared_ptr NullNATTraverser::createRemovePortForwardingRequest(int, int) { return boost::make_shared(eventLoop); } diff --git a/Swiften/Network/NullNATTraverser.h b/Swiften/Network/NullNATTraverser.h index 1b66a7d..5775a9b 100644 --- a/Swiften/Network/NullNATTraverser.h +++ b/Swiften/Network/NullNATTraverser.h @@ -16,8 +16,8 @@ namespace Swift { NullNATTraverser(EventLoop* eventLoop); boost::shared_ptr createGetPublicIPRequest(); - boost::shared_ptr createForwardPortRequest(unsigned int localPort, unsigned int publicPort); - boost::shared_ptr createRemovePortForwardingRequest(unsigned int localPort, unsigned int publicPort); + boost::shared_ptr createForwardPortRequest(int localPort, int publicPort); + boost::shared_ptr createRemovePortForwardingRequest(int localPort, int publicPort); private: EventLoop* eventLoop; diff --git a/Swiften/Network/PlatformNATTraversalRequest.cpp b/Swiften/Network/PlatformNATTraversalRequest.cpp deleted file mode 100644 index f875630..0000000 --- a/Swiften/Network/PlatformNATTraversalRequest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "PlatformNATTraversalRequest.h" - -#include - -namespace Swift { - -PlatformNATTraversalRequest::PlatformNATTraversalRequest(PlatformNATTraversalWorker* worker) : worker(worker) { - -} - -PlatformNATTraversalRequest::~PlatformNATTraversalRequest() { - -} - -void PlatformNATTraversalRequest::doRun() { - worker->addRequestToQueue(shared_from_this()); -} - -} diff --git a/Swiften/Network/PlatformNATTraversalRequest.h b/Swiften/Network/PlatformNATTraversalRequest.h deleted file mode 100644 index a891bab..0000000 --- a/Swiften/Network/PlatformNATTraversalRequest.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class PlatformNATTraversalWorker; - -class PlatformNATTraversalRequest : public boost::enable_shared_from_this { -public: - typedef boost::shared_ptr ref; - -public: - PlatformNATTraversalRequest(PlatformNATTraversalWorker* worker); - virtual ~PlatformNATTraversalRequest(); - - virtual void doRun(); - virtual void runBlocking() = 0; - -private: - PlatformNATTraversalWorker* worker; -}; - -} diff --git a/Swiften/Network/PlatformNATTraversalWorker.cpp b/Swiften/Network/PlatformNATTraversalWorker.cpp index e0dcab5..c962b3b 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.cpp +++ b/Swiften/Network/PlatformNATTraversalWorker.cpp @@ -7,18 +7,94 @@ #include "PlatformNATTraversalWorker.h" #include +#include + #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace Swift { -PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : backendType(NotYetDecided), eventLoop(eventLoop), stopRequested(false) { - checkAvailableNATTraversalProtocols(); +class PlatformNATTraversalRequest : public boost::enable_shared_from_this { + public: + typedef boost::shared_ptr ref; + + public: + PlatformNATTraversalRequest(PlatformNATTraversalWorker* worker) : worker(worker) { + } + + virtual ~PlatformNATTraversalRequest() { + } + + virtual void doRun() { + worker->addRequestToQueue(shared_from_this()); + } + + NATTraversalInterface* getNATTraversalInterface() const { + return worker->getNATTraversalInterface(); + } + + + virtual void runBlocking() = 0; + + private: + PlatformNATTraversalWorker* worker; +}; + +class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->getPublicIP()); + } +}; + +class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalForwardPortRequest(PlatformNATTraversalWorker* worker, unsigned int localIP, unsigned int publicIP) : PlatformNATTraversalRequest(worker), localIP(localIP), publicIP(publicIP) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->addPortForward(localIP, publicIP)); + } + + private: + unsigned int localIP; + unsigned int publicIP; +}; + +class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalRemovePortForwardingRequest(PlatformNATTraversalWorker* worker, const NATPortMapping& mapping) : PlatformNATTraversalRequest(worker), mapping(mapping) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->removePortForward(mapping)); + } + + private: + NATPortMapping mapping; +}; + +PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false), natPMPSupported(boost::logic::indeterminate), natPMPInterface(NULL), miniUPnPSupported(boost::logic::indeterminate), miniUPnPInterface(NULL) { + nullNATTraversalInterface = new NullNATTraversalInterface(); thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); } @@ -27,57 +103,43 @@ PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { addRequestToQueue(boost::shared_ptr()); thread->join(); delete thread; + delete natPMPInterface; + delete miniUPnPInterface; + delete nullNATTraversalInterface; } -boost::shared_ptr PlatformNATTraversalWorker::createGetPublicIPRequest() { - switch(backendType) { - case UPnP: - return boost::make_shared(this); - case NATPMP: - return boost::make_shared(this); - case NotYetDecided: - case None: - break; +NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() const { + if (boost::logic::indeterminate(miniUPnPSupported)) { + miniUPnPInterface = new MiniUPnPInterface(); + miniUPnPSupported = miniUPnPInterface->isAvailable(); + } + if (miniUPnPSupported) { + return miniUPnPInterface; } - return boost::shared_ptr(); -} -boost::shared_ptr PlatformNATTraversalWorker::createForwardPortRequest(unsigned int localPort, unsigned int publicPort) { - NATTraversalForwardPortRequest::PortMapping mapping; - mapping.protocol = NATTraversalForwardPortRequest::PortMapping::TCP; - mapping.leaseInSeconds = 60 * 60 * 24; - mapping.localPort = localPort; - mapping.publicPort = publicPort; - - switch(backendType) { - case UPnP: - return boost::make_shared(mapping, this); - case NATPMP: - return boost::make_shared(mapping, this); - case NotYetDecided: - case None: - break; + + if (boost::logic::indeterminate(natPMPSupported)) { + natPMPInterface = new NATPMPInterface(); + natPMPSupported = natPMPInterface->isAvailable(); + } + if (natPMPSupported) { + return natPMPInterface; } - return boost::shared_ptr(); + + return nullNATTraversalInterface; } -boost::shared_ptr PlatformNATTraversalWorker::createRemovePortForwardingRequest(unsigned int localPort, unsigned int publicPort) { - NATTraversalRemovePortForwardingRequest::PortMapping mapping; - mapping.protocol = NATTraversalRemovePortForwardingRequest::PortMapping::TCP; - mapping.leaseInSeconds = 60 * 60 * 24; - mapping.localPort = localPort; - mapping.publicPort = publicPort; - - switch(backendType) { - case UPnP: - return boost::make_shared(mapping, this); - case NATPMP: - return boost::make_shared(mapping, this); - case NotYetDecided: - case None: - break; - } - return boost::shared_ptr(); +boost::shared_ptr PlatformNATTraversalWorker::createGetPublicIPRequest() { + return boost::make_shared(this); +} + +boost::shared_ptr PlatformNATTraversalWorker::createForwardPortRequest(int localPort, int publicPort) { + return boost::make_shared(this, localPort, publicPort); +} + +boost::shared_ptr PlatformNATTraversalWorker::createRemovePortForwardingRequest(int localPort, int publicPort) { + NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); // FIXME + return boost::make_shared(this, mapping); } void PlatformNATTraversalWorker::run() { @@ -107,33 +169,4 @@ void PlatformNATTraversalWorker::addRequestToQueue(PlatformNATTraversalRequest:: queueNonEmpty.notify_one(); } -void PlatformNATTraversalWorker::checkAvailableNATTraversalProtocols() { - boost::shared_ptr upnpRequest = boost::make_shared(this); - upnpRequest->onResult.connect(boost::bind(&PlatformNATTraversalWorker::handleUPnPGetPublicIPResult, this, _1)); - - boost::shared_ptr natpmpRequest = boost::make_shared(this); - natpmpRequest->onResult.connect(boost::bind(&PlatformNATTraversalWorker::handleNATPMPGetPublicIPResult, this, _1)); - - upnpRequest->run(); - natpmpRequest->run(); -} - -void PlatformNATTraversalWorker::handleUPnPGetPublicIPResult(boost::optional address) { - if (backendType == NotYetDecided || backendType == None) { - if (address) { - SWIFT_LOG(debug) << "Found UPnP IGD in the local network." << std::endl; - backendType = UPnP; - } - } -} - -void PlatformNATTraversalWorker::handleNATPMPGetPublicIPResult(boost::optional address) { - if (backendType == NotYetDecided || backendType == None) { - if (address) { - SWIFT_LOG(debug) << "Found NAT-PMP device in the local network." << std::endl; - backendType = NATPMP; - } - } -} - } diff --git a/Swiften/Network/PlatformNATTraversalWorker.h b/Swiften/Network/PlatformNATTraversalWorker.h index 9de1258..94d3339 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.h +++ b/Swiften/Network/PlatformNATTraversalWorker.h @@ -11,51 +11,51 @@ #include #include #include +#include #include #include -#include +#include namespace Swift { - -class EventLoop; -class NATTraversalGetPublicIPRequest; -class NATTraversalForwardPortRequest; -class NATTraversalRemovePortForwardingRequest; - -class PlatformNATTraversalWorker : public NATTraverser { -private: - enum BackendType { - NotYetDecided, - UPnP, - NATPMP, - None, + class EventLoop; + class NATTraversalGetPublicIPRequest; + class NATTraversalForwardPortRequest; + class NATTraversalRemovePortForwardingRequest; + class PlatformNATTraversalRequest; + class NATPMPInterface; + class MiniUPnPInterface; + class NATTraversalInterface; + class NATPortMapping; + + class PlatformNATTraversalWorker : public NATTraverser { + friend class PlatformNATTraversalRequest; + + public: + PlatformNATTraversalWorker(EventLoop* eventLoop); + ~PlatformNATTraversalWorker(); + + boost::shared_ptr createGetPublicIPRequest(); + boost::shared_ptr createForwardPortRequest(int localPort, int publicPort); + boost::shared_ptr createRemovePortForwardingRequest(int localPort, int publicPort); + + private: + NATTraversalInterface* getNATTraversalInterface() const; + void addRequestToQueue(boost::shared_ptr); + void run(); + + private: + EventLoop* eventLoop; + bool stopRequested; + boost::thread* thread; + std::deque > queue; + boost::mutex queueMutex; + boost::condition_variable queueNonEmpty; + + NullNATTraversalInterface* nullNATTraversalInterface; + mutable boost::logic::tribool natPMPSupported; + mutable NATPMPInterface* natPMPInterface; + mutable boost::logic::tribool miniUPnPSupported; + mutable MiniUPnPInterface* miniUPnPInterface; }; - -public: - PlatformNATTraversalWorker(EventLoop* eventLoop); - ~PlatformNATTraversalWorker(); - - boost::shared_ptr createGetPublicIPRequest(); - boost::shared_ptr createForwardPortRequest(unsigned int localPort, unsigned int publicPort); - boost::shared_ptr createRemovePortForwardingRequest(unsigned int localPort, unsigned int publicPort); - - void run(); - void addRequestToQueue(PlatformNATTraversalRequest::ref); - -private: - void checkAvailableNATTraversalProtocols(); - void handleUPnPGetPublicIPResult(boost::optional address); - void handleNATPMPGetPublicIPResult(boost::optional address); - -private: - BackendType backendType; - EventLoop* eventLoop; - bool stopRequested; - boost::thread* thread; - std::deque queue; - boost::mutex queueMutex; - boost::condition_variable queueNonEmpty; -}; - } diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index e44f868..49df18f 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -47,6 +47,7 @@ sourceList = [ "NATTraversalGetPublicIPRequest.cpp", "NATTraversalForwardPortRequest.cpp", "NATTraversalRemovePortForwardingRequest.cpp", + "NATTraversalInterface.cpp", ] if myenv.get("HAVE_CARES", False) : @@ -75,22 +76,17 @@ if myenv["experimental"] : natpmp_env = myenv.Clone() natpmp_env.Append(CPPDEFINES = natpmp_env["LIBNATPMP_FLAGS"].get("INTERNAL_CPPDEFINES", [])) objects += natpmp_env.SwiftenObject([ - "NATPMPNATTraversalGetPublicIPRequest.cpp", - "NATPMPNATTraversalForwardPortRequest.cpp", - "NATPMPNATTraversalRemovePortForwardingRequest.cpp" + "NATPMPInterface.cpp", ]) # LibMINIUPnP classes upnp_env = myenv.Clone() upnp_env.Append(CPPDEFINES = upnp_env["LIBMINIUPNPC_FLAGS"].get("INTERNAL_CPPDEFINES", [])) objects += upnp_env.SwiftenObject([ - "UPnPNATTraversalGetPublicIPRequest.cpp", - "UPnPNATTraversalForwardPortRequest.cpp", - "UPnPNATTraversalRemovePortForwardingRequest.cpp", + "MiniUPnPInterface.cpp", ]) objects += myenv.SwiftenObject([ "PlatformNATTraversalWorker.cpp", - "PlatformNATTraversalRequest.cpp", - ]) + ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Network/UPnPNATTraversalForwardPortRequest.cpp b/Swiften/Network/UPnPNATTraversalForwardPortRequest.cpp deleted file mode 100644 index 6fcc01a..0000000 --- a/Swiften/Network/UPnPNATTraversalForwardPortRequest.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "UPnPNATTraversalForwardPortRequest.h" - -#include - -#include -#include -#include - -#include -#include -#include - -namespace Swift { - -UPnPNATTraversalForwardPortRequest::UPnPNATTraversalForwardPortRequest(NATTraversalForwardPortRequest::PortMapping mapping, PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker), mapping(mapping) { - -} - -UPnPNATTraversalForwardPortRequest::~UPnPNATTraversalForwardPortRequest() { - -} - -void UPnPNATTraversalForwardPortRequest::runBlocking() { - boost::optional result; - - UPNPDev* deviceList = 0; - int error = 0; - char lanAddrress[64]; - - std::string publicPort = str(boost::format("%d") % mapping.publicPort); - std::string localPort = str(boost::format("%d") % mapping.localPort); - std::string internalClient = PlatformNetworkEnvironment().getLocalAddress().toString(); - std::string leaseSeconds = str(boost::format("%d") % mapping.leaseInSeconds); - UPNPUrls urls; - IGDdatas data; - - do { - // find valid IGD - deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); - if (!deviceList) { - break; - } - - if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddrress, sizeof(lanAddrress))) { - break; - } - - /* - int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if (ret != UPNPCOMMAND_SUCCESS) { - break; - }*/ - - int ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), localPort.c_str(), internalClient.c_str(), 0, mapping.protocol == NATTraversalForwardPortRequest::PortMapping::TCP ? "TCP" : "UDP", 0, leaseSeconds.c_str()); - if (ret == UPNPCOMMAND_SUCCESS) { - result = boost::optional(mapping); - } - } while(false); - - freeUPNPDevlist(deviceList); deviceList = 0; - - onResult(result); -} - -} diff --git a/Swiften/Network/UPnPNATTraversalForwardPortRequest.h b/Swiften/Network/UPnPNATTraversalForwardPortRequest.h deleted file mode 100644 index 777ab26..0000000 --- a/Swiften/Network/UPnPNATTraversalForwardPortRequest.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class UPnPNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { -public: - UPnPNATTraversalForwardPortRequest(NATTraversalForwardPortRequest::PortMapping, PlatformNATTraversalWorker*); - virtual ~UPnPNATTraversalForwardPortRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } - -private: - NATTraversalForwardPortRequest::PortMapping mapping; -}; - -} diff --git a/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.cpp b/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.cpp deleted file mode 100644 index 4ed2f5f..0000000 --- a/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "UPnPNATTraversalGetPublicIPRequest.h" - -#include -#include -#include - -namespace Swift { - -UPnPNATTraversalGetPublicIPRequest::UPnPNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker) { - -} - -UPnPNATTraversalGetPublicIPRequest::~UPnPNATTraversalGetPublicIPRequest() { - -} - -void UPnPNATTraversalGetPublicIPRequest::runBlocking() { - boost::optional result; - - UPNPDev* deviceList = 0; - int error = 0; - char lanAddrress[64]; - char externalIPAddress[40]; - UPNPUrls urls; - IGDdatas data; - - do { - // find valid IGD - deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); - if (!deviceList) { - break; - } - - if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddrress, sizeof(lanAddrress))) { - break; - } - - int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if (ret != UPNPCOMMAND_SUCCESS) { - break; - } else { - result = HostAddress(std::string(externalIPAddress)); - } - } while(false); - - freeUPNPDevlist(deviceList); deviceList = 0; - - onResult(result); -} - -} diff --git a/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.h b/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.h deleted file mode 100644 index 884f1de..0000000 --- a/Swiften/Network/UPnPNATTraversalGetPublicIPRequest.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class UPnPNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest, public PlatformNATTraversalRequest { -public: - UPnPNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker*); - virtual ~UPnPNATTraversalGetPublicIPRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } -}; - -} diff --git a/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.cpp b/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.cpp deleted file mode 100644 index 9b83173..0000000 --- a/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "UPnPNATTraversalRemovePortForwardingRequest.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace Swift { - -UPnPNATTraversalRemovePortForwardingRequest::UPnPNATTraversalRemovePortForwardingRequest(NATTraversalRemovePortForwardingRequest::PortMapping mapping, PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker), mapping(mapping) { - -} - -UPnPNATTraversalRemovePortForwardingRequest::~UPnPNATTraversalRemovePortForwardingRequest() { - -} - -void UPnPNATTraversalRemovePortForwardingRequest::runBlocking() { - boost::optional result; - - UPNPDev* deviceList = 0; - int error = 0; - char lanAddrress[64]; - - std::string publicPort = str(boost::format("%d") % mapping.publicPort); - std::string localPort = str(boost::format("%d") % mapping.localPort); - std::string internalClient = PlatformNetworkEnvironment().getLocalAddress().toString(); - std::string leaseSeconds = str(boost::format("%d") % mapping.leaseInSeconds); - UPNPUrls urls; - IGDdatas data; - - do { - // find valid IGD - deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); - if (!deviceList) { - break; - } - - if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddrress, sizeof(lanAddrress))) { - break; - } - - /* - int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if (ret != UPNPCOMMAND_SUCCESS) { - break; - }*/ - SWIFT_LOG(debug) << "Start removing port forwarding..." << std::endl; - int ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), mapping.protocol == NATTraversalRemovePortForwardingRequest::PortMapping::TCP ? "TCP" : "UDP", 0); - - if (ret == UPNPCOMMAND_SUCCESS) { - SWIFT_LOG(debug) << "Removing port " << publicPort << " successfull." << std::endl; - result = true; - } else { - SWIFT_LOG(debug) << "Removing port " << publicPort << " failed." << std::endl; - result = false; - } - } while(false); - - freeUPNPDevlist(deviceList); deviceList = 0; - - onResult(result); -} - -} diff --git a/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.h b/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.h deleted file mode 100644 index 644eae7..0000000 --- a/Swiften/Network/UPnPNATTraversalRemovePortForwardingRequest.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -namespace Swift { - -class UPnPNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { -public: - UPnPNATTraversalRemovePortForwardingRequest(NATTraversalRemovePortForwardingRequest::PortMapping, PlatformNATTraversalWorker*); - virtual ~UPnPNATTraversalRemovePortForwardingRequest(); - - virtual void runBlocking(); - - virtual void run() { - doRun(); - } - -private: - NATTraversalRemovePortForwardingRequest::PortMapping mapping; -}; - -} -- cgit v0.10.2-6-g49f6