mirror of
https://bitbucket.org/King_DuckZ/keepupnpup.git
synced 2024-11-07 21:29:00 +00:00
Refactor code into separate files.
This commit is contained in:
parent
be95a0f959
commit
308e364201
5 changed files with 483 additions and 263 deletions
|
@ -23,6 +23,7 @@ endif()
|
|||
|
||||
add_executable(${PROJECT_NAME}
|
||||
src/main.cpp
|
||||
src/upnp.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
|
@ -45,4 +46,4 @@ else()
|
|||
)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
|
||||
|
|
287
src/main.cpp
287
src/main.cpp
|
@ -15,287 +15,50 @@
|
|||
* along with "keepupnpup". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "upnp.hpp"
|
||||
#include <iostream>
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "upnperrors.h"
|
||||
#include "enum.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ciso646>
|
||||
#include <cstdint>
|
||||
#include <strings.h>
|
||||
#include <array>
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define KUU_VERBOSE
|
||||
#endif
|
||||
|
||||
BETTER_ENUM (Protocol, uint8_t,
|
||||
UDP,
|
||||
TCP,
|
||||
Other
|
||||
);
|
||||
|
||||
namespace {
|
||||
class UPNPUrlsResource {
|
||||
public:
|
||||
enum IGDReply {
|
||||
IGDValid = 1,
|
||||
IGDNotConnected = 2,
|
||||
IGDUpnpNotSureIGD = 3,
|
||||
IGDNotSure,
|
||||
IGDNone
|
||||
};
|
||||
|
||||
explicit UPNPUrlsResource (struct UPNPDev* parDevList) :
|
||||
m_lanaddr(),
|
||||
m_externaladdr(),
|
||||
m_igd_reply(IGDNone)
|
||||
{
|
||||
{
|
||||
std::array<char, 64> lanaddr;
|
||||
const auto i = UPNP_GetValidIGD(parDevList, &m_urls, &m_data, lanaddr.data(), lanaddr.size());
|
||||
|
||||
switch (i) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
m_igd_reply = static_cast<IGDReply>(i);
|
||||
break;
|
||||
default:
|
||||
m_igd_reply = IGDNotSure;
|
||||
}
|
||||
|
||||
m_lanaddr = lanaddr.data();
|
||||
}
|
||||
|
||||
{
|
||||
std::array<char, 64> externaladdr;
|
||||
const auto r = UPNP_GetExternalIPAddress(m_urls.controlURL, m_data.first.servicetype, externaladdr.data());
|
||||
if (UPNPCOMMAND_SUCCESS != r)
|
||||
m_externaladdr = externaladdr.data();
|
||||
}
|
||||
}
|
||||
|
||||
~UPNPUrlsResource() noexcept {
|
||||
if (IGDNone != m_igd_reply) {
|
||||
m_igd_reply = IGDNone;
|
||||
FreeUPNPUrls(&m_urls);
|
||||
}
|
||||
}
|
||||
|
||||
const struct UPNPUrls* urls() const { return &m_urls; }
|
||||
const struct IGDdatas* data() const { return &m_data; }
|
||||
IGDReply igd_reply() const { return m_igd_reply; }
|
||||
const std::string& lanaddr() const { return m_lanaddr; }
|
||||
const std::string& externaladdr() const { return m_externaladdr; }
|
||||
|
||||
private:
|
||||
std::string m_lanaddr;
|
||||
std::string m_externaladdr;
|
||||
struct UPNPUrls m_urls;
|
||||
struct IGDdatas m_data;
|
||||
IGDReply m_igd_reply;
|
||||
};
|
||||
|
||||
struct Redirection {
|
||||
Redirection() : protocol(Protocol::Other) {}
|
||||
|
||||
std::string internal_client;
|
||||
std::string remote_host;
|
||||
std::string desc;
|
||||
Protocol protocol;
|
||||
uint32_t duration;
|
||||
uint16_t internal_port;
|
||||
uint16_t external_port;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
using UPNPDevsPtr = std::unique_ptr<struct UPNPDev, void(*)(struct UPNPDev*)>;
|
||||
|
||||
std::vector<struct UPNPDev*> dev_list_to_vector (struct UPNPDev* parList) {
|
||||
std::vector<struct UPNPDev*> retval;
|
||||
for (auto dev = parList; dev; dev = dev->pNext) {
|
||||
retval.push_back(dev);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool is_enabled (const std::string& parEnabled) {
|
||||
if (parEnabled.size() == 4) {
|
||||
if (strncasecmp("true", parEnabled.c_str(), 4) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (parEnabled.size() == 2) {
|
||||
if (strncasecmp("on", parEnabled.c_str(), 2) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (parEnabled.size() == 3) {
|
||||
if (strncasecmp("yes", parEnabled.c_str(), 3) == 0)
|
||||
return true;
|
||||
}
|
||||
if (parEnabled == "1")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Redirection> get_redirections (const UPNPUrlsResource& parResource) {
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
char extPort[6];
|
||||
char protocol[4];
|
||||
char desc[80];
|
||||
char enabled[6];
|
||||
char rHost[64];
|
||||
char duration[16];
|
||||
int r;
|
||||
|
||||
int z = 0;
|
||||
std::vector<Redirection> retval;
|
||||
do {
|
||||
rHost[0] = '\0';
|
||||
enabled[0] = '\0';
|
||||
duration[0] = '\0';
|
||||
desc[0] = '\0';
|
||||
extPort[0] = '\0';
|
||||
intPort[0] = '\0';
|
||||
intClient[0] = '\0';
|
||||
|
||||
r = UPNP_GetGenericPortMappingEntry(
|
||||
parResource.urls()->controlURL,
|
||||
parResource.data()->first.servicetype,
|
||||
std::to_string(z).c_str(),
|
||||
extPort,
|
||||
intClient,
|
||||
intPort,
|
||||
protocol,
|
||||
desc,
|
||||
enabled,
|
||||
rHost,
|
||||
duration
|
||||
);
|
||||
|
||||
//if (r)
|
||||
// printf("GetGenericPortMappingEntry() returned %d (%s)\n",
|
||||
// r, strupnperror(r));
|
||||
|
||||
if (not r) {
|
||||
Redirection redir;
|
||||
better_enums::optional<Protocol> proto = Protocol::_from_string_nothrow(protocol);
|
||||
redir.protocol = (proto ? *proto : +Protocol::Other);
|
||||
redir.internal_client = intClient;
|
||||
redir.remote_host = rHost;
|
||||
redir.desc = desc;
|
||||
redir.duration = static_cast<uint32_t>(stoul(std::string(duration)));
|
||||
redir.internal_port = static_cast<uint16_t>(stoul(std::string(intPort)));
|
||||
redir.external_port = static_cast<uint16_t>(stoul(std::string(extPort)));
|
||||
redir.enabled = is_enabled(std::string(enabled));
|
||||
|
||||
retval.push_back(redir);
|
||||
}
|
||||
|
||||
++z;
|
||||
} while (not r);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void add_port_mapping (
|
||||
const UPNPUrlsResource& parResource,
|
||||
uint16_t parExtPort,
|
||||
uint16_t parIntPort,
|
||||
const std::string& parAddr,
|
||||
const std::string& parDesc,
|
||||
uint32_t parDuration,
|
||||
Protocol parProtocol
|
||||
) {
|
||||
const auto r = UPNP_AddPortMapping(
|
||||
parResource.urls()->controlURL,
|
||||
parResource.data()->first.servicetype,
|
||||
std::to_string(parExtPort).c_str(),
|
||||
std::to_string(parIntPort).c_str(),
|
||||
parAddr.c_str(),
|
||||
parDesc.c_str(),
|
||||
parProtocol._to_string(),
|
||||
0,
|
||||
std::to_string(parDuration).c_str()
|
||||
);
|
||||
//if (UPNPCOMMAND_SUCCESS != r)
|
||||
//printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
//eport, iport, iaddr, r, strupnperror(r));
|
||||
}
|
||||
|
||||
bool has_mapping (const std::vector<Redirection>& parRedirs, const std::string& parAddr, uint16_t parPort, Protocol parProtocol) {
|
||||
bool has_mapping (const std::vector<kuu::Redirection>& 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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void runapp() {
|
||||
kuu::UPNP upnp;
|
||||
|
||||
const auto redirs = upnp.redirections();
|
||||
|
||||
if (not has_mapping(redirs, upnp.lanaddr(), 6881, kuu::Protocol::TCP))
|
||||
upnp.add_port_mapping(6881, 6881, upnp.lanaddr(), "RoutArm redir", 0, kuu::Protocol::TCP);
|
||||
if (not has_mapping(redirs, upnp.lanaddr(), 49164, kuu::Protocol::TCP))
|
||||
upnp.add_port_mapping(49164, 49164, upnp.lanaddr(), "RoutArm redir", 0, kuu::Protocol::TCP);
|
||||
if (not has_mapping(redirs, upnp.lanaddr(), 49164, kuu::Protocol::UDP))
|
||||
upnp.add_port_mapping(49164, 49164, upnp.lanaddr(), "RoutArm redir", 0, kuu::Protocol::UDP);
|
||||
|
||||
//for (auto& redir : redirs) {
|
||||
// std::cout << redir.protocol << ", " << redir.remote_host << ":" << redir.external_port << " --> " <<
|
||||
// redir.internal_client << ":" << redir.internal_port << ", " << redir.duration << ", " <<
|
||||
// redir.enabled << R"(, ")" << redir.desc << "\"\n";
|
||||
//}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
int error;
|
||||
UPNPDevsPtr devlist(nullptr, &freeUPNPDevlist);
|
||||
|
||||
devlist.reset(upnpDiscover(
|
||||
2000,
|
||||
nullptr, //multicastif
|
||||
nullptr, //minissdpdpath
|
||||
UPNP_LOCAL_PORT_ANY, //localport
|
||||
0, //ipv6
|
||||
2, //ttl
|
||||
&error
|
||||
));
|
||||
|
||||
const auto devs = dev_list_to_vector(devlist.get());
|
||||
if (devs.empty()) {
|
||||
std::cerr << "No UPNP devices found\n";
|
||||
return 1;
|
||||
try {
|
||||
runapp();
|
||||
}
|
||||
else if (devs.size() > 1) {
|
||||
std::cerr << "More than one UPNP device found (" << devs.size() << "), aborting\n";
|
||||
catch (const kuu::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
UPNPUrlsResource urls(devlist.get());
|
||||
|
||||
#if defined(KUU_VERBOSE)
|
||||
std::cout << "Found: " << devs.front()->descURL << ", " << devs.front()->st << '\n';
|
||||
|
||||
switch (urls.igd_reply()) {
|
||||
case UPNPUrlsResource::IGDValid:
|
||||
std::cout << "Found valid IGD: " << urls.urls()->controlURL << '\n';
|
||||
break;
|
||||
case UPNPUrlsResource::IGDNotConnected:
|
||||
std::cout << "Found a (not connected?) IGD: " << urls.urls()->controlURL << '\n';
|
||||
break;
|
||||
case UPNPUrlsResource::IGDUpnpNotSureIGD:
|
||||
std::cout << "UPnP device found. Is it an IGD? " << urls.urls()->controlURL << '\n';
|
||||
break;
|
||||
case UPNPUrlsResource::IGDNotSure:
|
||||
std::cout << "Found device (igd?): " << urls.urls()->controlURL << '\n';
|
||||
}
|
||||
|
||||
std::cout << "Local LAN ip address: " << urls.lanaddr() << '\n';
|
||||
std::cout << "External ip address: " << urls.externaladdr() << '\n';
|
||||
#endif
|
||||
|
||||
const auto redirs = get_redirections(urls);
|
||||
|
||||
if (not has_mapping(redirs, urls.lanaddr(), 6881, Protocol::TCP))
|
||||
add_port_mapping(urls, 6881, 6881, urls.lanaddr(), "RoutArm redir", 0, Protocol::TCP);
|
||||
if (not has_mapping(redirs, urls.lanaddr(), 49164, Protocol::TCP))
|
||||
add_port_mapping(urls, 49164, 49164, urls.lanaddr(), "RoutArm redir", 0, Protocol::TCP);
|
||||
if (not has_mapping(redirs, urls.lanaddr(), 49164, Protocol::UDP))
|
||||
add_port_mapping(urls, 49164, 49164, urls.lanaddr(), "RoutArm redir", 0, Protocol::UDP);
|
||||
|
||||
//for (auto& redir : redirs) {
|
||||
// std::cout << redir.protocol << ", " << redir.remote_host << ":" << redir.external_port << " --> " <<
|
||||
// redir.internal_client << ":" << redir.internal_port << ", " << redir.duration << ", " <<
|
||||
// redir.enabled << R"(, ")" << redir.desc << "\"\n";
|
||||
//}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
43
src/redirection.hpp
Normal file
43
src/redirection.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Copyright 2016, Michele Santullo
|
||||
* This file is part of "keepupnpup".
|
||||
*
|
||||
* "keepupnpup" is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "keepupnpup" is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with "keepupnpup". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum.h"
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace kuu {
|
||||
BETTER_ENUM (Protocol, uint8_t,
|
||||
UDP,
|
||||
TCP,
|
||||
Other
|
||||
);
|
||||
|
||||
struct Redirection {
|
||||
Redirection() : protocol(Protocol::Other) {}
|
||||
|
||||
std::string internal_client;
|
||||
std::string remote_host;
|
||||
std::string desc;
|
||||
Protocol protocol;
|
||||
uint32_t duration;
|
||||
uint16_t internal_port;
|
||||
uint16_t external_port;
|
||||
bool enabled;
|
||||
};
|
||||
} //namespace kuu
|
330
src/upnp.cpp
Normal file
330
src/upnp.cpp
Normal file
|
@ -0,0 +1,330 @@
|
|||
/* Copyright 2016, Michele Santullo
|
||||
* This file is part of "keepupnpup".
|
||||
*
|
||||
* "keepupnpup" is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "keepupnpup" is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with "keepupnpup". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "upnp.hpp"
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "upnperrors.h"
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <ciso646>
|
||||
#include <strings.h>
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define KUU_VERBOSE
|
||||
#endif
|
||||
|
||||
#if defined(KUU_VERBOSE)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
namespace kuu {
|
||||
namespace {
|
||||
struct UPNPUrlsWithInitFlag {
|
||||
UPNPUrlsWithInitFlag() : initialized(false) {}
|
||||
struct UPNPUrls urls;
|
||||
bool initialized;
|
||||
|
||||
operator struct UPNPUrls* () { return &urls; }
|
||||
UPNPUrlsWithInitFlag* operator-> () { return this; }
|
||||
};
|
||||
|
||||
//see: http://stackoverflow.com/questions/24611215/one-liner-for-raii-on-non-pointer
|
||||
struct UPNPUrlDeleter {
|
||||
typedef UPNPUrlsWithInitFlag pointer;
|
||||
void operator() (UPNPUrlsWithInitFlag& parUrls) {
|
||||
if (parUrls.initialized) {
|
||||
parUrls.initialized = false;
|
||||
FreeUPNPUrls(&parUrls.urls);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using UPNPUrlsPtr = std::unique_ptr<UPNPUrlsWithInitFlag, UPNPUrlDeleter>;
|
||||
using UPNPDevsPtr = std::unique_ptr<struct UPNPDev, void(*)(struct UPNPDev*)>;
|
||||
|
||||
std::vector<struct UPNPDev*> dev_list_to_vector (struct UPNPDev* parList) {
|
||||
std::vector<struct UPNPDev*> retval;
|
||||
for (auto dev = parList; dev; dev = dev->pNext) {
|
||||
retval.push_back(dev);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string build_exception_msg (int parError, const char* parMessageIntro, const char* parMessage) {
|
||||
std::ostringstream oss;
|
||||
oss << parMessageIntro << " (" << parError << ")";
|
||||
if (parMessage)
|
||||
oss << ": \"" << parMessage << '"';
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool is_enabled (const std::string& parEnabled) {
|
||||
if (parEnabled.size() == 4) {
|
||||
if (strncasecmp("true", parEnabled.c_str(), 4) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (parEnabled.size() == 2) {
|
||||
if (strncasecmp("on", parEnabled.c_str(), 2) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (parEnabled.size() == 3) {
|
||||
if (strncasecmp("yes", parEnabled.c_str(), 3) == 0)
|
||||
return true;
|
||||
}
|
||||
if (parEnabled == "1")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(KUU_VERBOSE)
|
||||
void print_devices (
|
||||
const std::vector<struct UPNPDev*>& parDevs,
|
||||
struct UPNPUrls* parUrls,
|
||||
UPNP::IGDReply parIGDReply,
|
||||
const std::string& parLanAddr,
|
||||
const std::string& parExternalAddr
|
||||
) {
|
||||
std::cout << "Found: " << parDevs.front()->descURL << ", " << parDevs.front()->st << '\n';
|
||||
|
||||
switch (parIGDReply) {
|
||||
case UPNP::IGDValid:
|
||||
std::cout << "Found valid IGD: " << parUrls->controlURL << '\n';
|
||||
break;
|
||||
case UPNP::IGDNotConnected:
|
||||
std::cout << "Found a (not connected?) IGD: " << parUrls->controlURL << '\n';
|
||||
break;
|
||||
case UPNP::IGDUpnpNotSureIGD:
|
||||
std::cout << "UPnP device found. Is it an IGD? " << parUrls->controlURL << '\n';
|
||||
break;
|
||||
case UPNP::IGDNotSure:
|
||||
std::cout << "Found device (igd?): " << parUrls->controlURL << '\n';
|
||||
}
|
||||
|
||||
std::cout << "Local LAN ip address: " << parLanAddr << '\n';
|
||||
std::cout << "External ip address: " << parExternalAddr << '\n';
|
||||
}
|
||||
#endif
|
||||
|
||||
} //unnamed namespace
|
||||
|
||||
struct UPNP::LocalData {
|
||||
|
||||
LocalData() :
|
||||
lanaddr(),
|
||||
externaladdr(),
|
||||
igd_reply(IGDNone),
|
||||
devlist(nullptr, &freeUPNPDevlist)
|
||||
{
|
||||
}
|
||||
|
||||
std::string lanaddr;
|
||||
std::string externaladdr;
|
||||
struct IGDdatas data;
|
||||
IGDReply igd_reply;
|
||||
UPNPDevsPtr devlist;
|
||||
UPNPUrlsPtr urls;
|
||||
};
|
||||
|
||||
UPNP::UPNP() :
|
||||
m_local_data(std::make_unique<LocalData>())
|
||||
{
|
||||
int error;
|
||||
UPNPDevsPtr devlist(
|
||||
upnpDiscover(
|
||||
2000,
|
||||
nullptr, //multicastif
|
||||
nullptr, //minissdpdpath
|
||||
UPNP_LOCAL_PORT_ANY, //localport
|
||||
0, //ipv6
|
||||
2, //ttl
|
||||
&error
|
||||
),
|
||||
&freeUPNPDevlist
|
||||
);
|
||||
if (error)
|
||||
throw UPNPException(error, "Error initializing upnpc in upnpDiscover()", nullptr);
|
||||
|
||||
const auto devs = dev_list_to_vector(devlist.get());
|
||||
if (devs.empty())
|
||||
throw ScanException("No UPNP devices found");
|
||||
else if (devs.size() > 1)
|
||||
throw ScanException("More than one UPNP device found (" + std::to_string(devs.size()) + ")");
|
||||
|
||||
UPNPUrlsPtr urls;
|
||||
{
|
||||
std::array<char, 64> lanaddr;
|
||||
const auto i = UPNP_GetValidIGD(
|
||||
devlist.get(),
|
||||
urls.get(),
|
||||
&m_local_data->data,
|
||||
lanaddr.data(),
|
||||
lanaddr.size()
|
||||
);
|
||||
|
||||
switch (i) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
m_local_data->igd_reply = static_cast<IGDReply>(i);
|
||||
break;
|
||||
default:
|
||||
m_local_data->igd_reply = IGDNotSure;
|
||||
}
|
||||
urls->initialized = true;
|
||||
|
||||
m_local_data->lanaddr = lanaddr.data();
|
||||
}
|
||||
|
||||
{
|
||||
std::array<char, 64> externaladdr;
|
||||
const auto r = UPNP_GetExternalIPAddress(urls->urls.controlURL, m_local_data->data.first.servicetype, externaladdr.data());
|
||||
if (UPNPCOMMAND_SUCCESS != r)
|
||||
m_local_data->externaladdr = externaladdr.data();
|
||||
}
|
||||
|
||||
#if defined(KUU_VERBOSE)
|
||||
print_devices(devs, urls.get(), m_local_data->igd_reply, m_local_data->lanaddr, m_local_data->externaladdr);
|
||||
#endif
|
||||
m_local_data->urls.swap(urls);
|
||||
m_local_data->devlist.swap(devlist);
|
||||
}
|
||||
|
||||
UPNP::~UPNP() noexcept = default;
|
||||
|
||||
UPNP::IGDReply UPNP::igd_reply() const {
|
||||
return m_local_data->igd_reply;
|
||||
}
|
||||
|
||||
const std::string& UPNP::lanaddr() const {
|
||||
return m_local_data->lanaddr;
|
||||
}
|
||||
|
||||
const std::string& UPNP::externaladdr() const {
|
||||
return m_local_data->externaladdr;
|
||||
}
|
||||
|
||||
std::vector<Redirection> UPNP::redirections() const {
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
char extPort[6];
|
||||
char protocol[4];
|
||||
char desc[80];
|
||||
char enabled[6];
|
||||
char rHost[64];
|
||||
char duration[16];
|
||||
int r;
|
||||
|
||||
int z = 0;
|
||||
std::vector<Redirection> retval;
|
||||
do {
|
||||
rHost[0] = '\0';
|
||||
enabled[0] = '\0';
|
||||
duration[0] = '\0';
|
||||
desc[0] = '\0';
|
||||
extPort[0] = '\0';
|
||||
intPort[0] = '\0';
|
||||
intClient[0] = '\0';
|
||||
|
||||
r = UPNP_GetGenericPortMappingEntry(
|
||||
m_local_data->urls->urls.controlURL,
|
||||
m_local_data->data.first.servicetype,
|
||||
std::to_string(z).c_str(),
|
||||
extPort,
|
||||
intClient,
|
||||
intPort,
|
||||
protocol,
|
||||
desc,
|
||||
enabled,
|
||||
rHost,
|
||||
duration
|
||||
);
|
||||
|
||||
if (not r) {
|
||||
Redirection redir;
|
||||
better_enums::optional<Protocol> proto = Protocol::_from_string_nothrow(protocol);
|
||||
redir.protocol = (proto ? *proto : +Protocol::Other);
|
||||
redir.internal_client = intClient;
|
||||
redir.remote_host = rHost;
|
||||
redir.desc = desc;
|
||||
redir.duration = static_cast<uint32_t>(stoul(std::string(duration)));
|
||||
redir.internal_port = static_cast<uint16_t>(stoul(std::string(intPort)));
|
||||
redir.external_port = static_cast<uint16_t>(stoul(std::string(extPort)));
|
||||
redir.enabled = is_enabled(std::string(enabled));
|
||||
|
||||
retval.push_back(redir);
|
||||
}
|
||||
else {
|
||||
throw UPNPException(r, "Error in invocation of UPNP_GetGenericPortMappingEntry()", strupnperror(r));
|
||||
}
|
||||
|
||||
++z;
|
||||
} while (not r);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void UPNP::add_port_mapping (
|
||||
uint16_t parExtPort,
|
||||
uint16_t parIntPort,
|
||||
const std::string& parAddr,
|
||||
const std::string& parDesc,
|
||||
uint32_t parDuration,
|
||||
Protocol parProtocol
|
||||
) {
|
||||
const auto r = UPNP_AddPortMapping(
|
||||
m_local_data->urls->urls.controlURL,
|
||||
m_local_data->data.first.servicetype,
|
||||
std::to_string(parExtPort).c_str(),
|
||||
std::to_string(parIntPort).c_str(),
|
||||
parAddr.c_str(),
|
||||
parDesc.c_str(),
|
||||
parProtocol._to_string(),
|
||||
0,
|
||||
std::to_string(parDuration).c_str()
|
||||
);
|
||||
if (UPNPCOMMAND_SUCCESS != r) {
|
||||
std::ostringstream oss;
|
||||
oss << "Error in UPNP_AddPortMapping(\"" <<
|
||||
m_local_data->urls->urls.controlURL << "\", \"" <<
|
||||
m_local_data->data.first.servicetype << "\", " <<
|
||||
parExtPort << ", " <<
|
||||
parIntPort << ", \"" <<
|
||||
parAddr << "\", \"" <<
|
||||
parDesc << "\", " <<
|
||||
parProtocol._to_string() << ")";
|
||||
throw UPNPException(r, oss.str().c_str(), strupnperror(r));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UPNPException::UPNPException (int parError, const char* parMessageIntro, const char* parMessage) :
|
||||
Exception(build_exception_msg(parError, parMessageIntro, parMessage)),
|
||||
m_error(parError)
|
||||
{
|
||||
}
|
||||
|
||||
ScanException::ScanException (const std::string& parMessage) :
|
||||
Exception(parMessage)
|
||||
{
|
||||
}
|
||||
|
||||
ScanException::ScanException (const char* parMessage) :
|
||||
Exception(parMessage)
|
||||
{
|
||||
}
|
||||
} //namespace kuu
|
83
src/upnp.hpp
Normal file
83
src/upnp.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Copyright 2016, Michele Santullo
|
||||
* This file is part of "keepupnpup".
|
||||
*
|
||||
* "keepupnpup" is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "keepupnpup" is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with "keepupnpup". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "redirection.hpp"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace kuu {
|
||||
class UPNP {
|
||||
public:
|
||||
enum IGDReply {
|
||||
IGDValid = 1,
|
||||
IGDNotConnected = 2,
|
||||
IGDUpnpNotSureIGD = 3,
|
||||
IGDNotSure,
|
||||
IGDNone
|
||||
};
|
||||
|
||||
UPNP();
|
||||
~UPNP() noexcept;
|
||||
|
||||
IGDReply igd_reply() const;
|
||||
const std::string& lanaddr() const;
|
||||
const std::string& externaladdr() const;
|
||||
std::vector<Redirection> redirections() const;
|
||||
|
||||
void add_port_mapping (
|
||||
uint16_t parExtPort,
|
||||
uint16_t parIntPort,
|
||||
const std::string& parAddr,
|
||||
const std::string& parDesc,
|
||||
uint32_t parDuration,
|
||||
Protocol parProtocol
|
||||
);
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::unique_ptr<LocalData> m_local_data;
|
||||
};
|
||||
|
||||
class Exception : public std::runtime_error {
|
||||
protected:
|
||||
explicit Exception (const char* parMessage) : std::runtime_error(parMessage) {}
|
||||
explicit Exception (const std::string& parMessage) : std::runtime_error(parMessage) {}
|
||||
};
|
||||
|
||||
class UPNPException : public Exception {
|
||||
public:
|
||||
UPNPException (int parError, const char* parMessageIntro, const char* parMessage);
|
||||
virtual ~UPNPException() noexcept = default;
|
||||
|
||||
int error_code() const { return m_error; }
|
||||
|
||||
private:
|
||||
int m_error;
|
||||
};
|
||||
|
||||
class ScanException : public Exception {
|
||||
public:
|
||||
explicit ScanException (const char* parMessage);
|
||||
explicit ScanException (const std::string& parMessage);
|
||||
};
|
||||
} //namespace kuu
|
Loading…
Reference in a new issue