diff --git a/src/main.cpp b/src/main.cpp index 54d977a..f26f93a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,12 +23,18 @@ #include namespace { - bool has_mapping (const std::vector& parRedirs, const std::string& parAddr, uint16_t parPort, kuu::Protocol parProtocol) { + enum CurrentMappingType { + NoMapping, + PresentWithSameIP, + PresentWithDifferentIP + }; + + CurrentMappingType has_mapping (const std::vector& parRedirs, const std::string& parAddr, uint16_t parPort, kuu::Protocol parProtocol) { for (auto& redir : parRedirs) { - if (redir.protocol == parProtocol and redir.internal_port == parPort and redir.internal_client == parAddr) - return true; + if (redir.protocol == parProtocol and redir.internal_port == parPort) + return (redir.internal_client == parAddr ? PresentWithSameIP : PresentWithDifferentIP); } - return false; + return NoMapping; } void add_bindings (kuu::UPNP& parUpnp, const std::string& parHost, const kuu::RedirectSetting::PortMappingsList& parPortMappings, const std::string& parDesc) { @@ -36,8 +42,26 @@ namespace { for (auto& mapping : parPortMappings) { //std::cout << "Adding " << mapping.port << " --> " << parHost << ":" << mapping.internal_port << " " << mapping.protocol << '\n'; - if (not has_mapping(redirs, parHost, mapping.port, mapping.protocol)) - parUpnp.add_port_mapping(mapping.port, mapping.internal_port, parHost, parDesc, 0, mapping.protocol); + bool try_add_mapping = true; + try { + const CurrentMappingType curr_mapping = + has_mapping(redirs, parHost, mapping.port, mapping.protocol); + + switch (curr_mapping) { + case PresentWithDifferentIP: + parUpnp.remove_port_mapping(mapping.port, parHost, mapping.protocol); + + case NoMapping: + parUpnp.add_port_mapping(mapping.port, mapping.internal_port, parHost, parDesc, 0, mapping.protocol); + break; + + case PresentWithSameIP: + break; + }; + } + catch (const kuu::UPNPException& e) { + std::cerr << e.what() << std::endl; + } } } diff --git a/src/upnp.cpp b/src/upnp.cpp index 215c9f4..eb99d40 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -19,12 +19,14 @@ #include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" +#include "enum.h" #include #include #include #include #include #include +#include #if !defined(NDEBUG) # define KUU_VERBOSE @@ -35,6 +37,12 @@ #endif namespace kuu { + BETTER_ENUM(UPNPDeleteErrors, uint16_t, + InvalidArgs = 402, //See UPnP Device Architecture section on Control. + NotAuthorized = 606, //The action requested REQUIRES authorization and the sender was not authorized. + NoSuchEntryInArray = 714 //The specified value does not exist in the array + ); + namespace { void freeUPNPDevlist (struct UPNPDev* parDele) { #if defined(KUU_VERBOSE) @@ -328,4 +336,48 @@ namespace kuu { throw UPNPException(r, oss.str().c_str(), strupnperror(r)); } } + + void throw_if_dele_failed (int parRetval, uint16_t parExtPort, const std::string& parAddr, Protocol parProtocol) { + if (not parRetval) + return; + + std::ostringstream oss; + oss << "Unable to delete " << parProtocol << ' ' << parAddr << + ':' << parExtPort << " - error " << parRetval << ": "; + + switch (parRetval) { + case UPNPDeleteErrors::NotAuthorized: + oss << "The action requested REQUIRES authorization and the sender was not authorized"; + break; + + case UPNPDeleteErrors::NoSuchEntryInArray: + oss << "The specified value does not exist in the array"; + break; + + case UPNPDeleteErrors::InvalidArgs: + oss << "See UPnP Device Architecture section on Control"; + break; + + default: + oss << "Unknown error"; + } + + throw UPNPException(parRetval, oss.str().c_str(), strupnperror(parRetval)); + } + + void UPNP::remove_port_mapping ( + uint16_t parExtPort, + const std::string& parAddr, + Protocol parProtocol + ) { + const int dele_retval = UPNP_DeletePortMapping( + m_local_data->urls->controlURL, + m_local_data->data.first.servicetype, + std::to_string(parExtPort).c_str(), + parProtocol._to_string(), + parAddr.c_str() + ); + + throw_if_dele_failed(dele_retval, parExtPort, parAddr, parProtocol); + } } //namespace kuu diff --git a/src/upnp.hpp b/src/upnp.hpp index 0f1a5f3..2961fce 100644 --- a/src/upnp.hpp +++ b/src/upnp.hpp @@ -52,6 +52,12 @@ namespace kuu { Protocol parProtocol ); + void remove_port_mapping ( + uint16_t parExtPort, + const std::string& parAddr, + Protocol parProtocol + ); + private: struct LocalData;