Browse Source

correct termination of UPnP

pull/578/head
orignal 8 years ago
parent
commit
b7c5e3b5d5
  1. 121
      UPnP.cpp
  2. 22
      UPnP.h

121
UPnP.cpp

@ -21,47 +21,52 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
UPnP::UPnP () : m_Thread (nullptr) UPnP::UPnP () : m_IsRunning(false), m_Thread (nullptr), m_Timer (m_Service)
{ {
} }
void UPnP::Stop () void UPnP::Stop ()
{
if (m_IsRunning)
{ {
LogPrint(eLogInfo, "UPnP: stopping"); LogPrint(eLogInfo, "UPnP: stopping");
m_IsRunning = false;
m_Timer.cancel ();
m_Service.stop ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; m_Thread.reset (nullptr);
m_Thread = nullptr; }
CloseMapping ();
Close ();
} }
} }
void UPnP::Start() void UPnP::Start()
{ {
m_IsRunning = true;
LogPrint(eLogInfo, "UPnP: starting"); LogPrint(eLogInfo, "UPnP: starting");
m_Thread = new std::thread (std::bind (&UPnP::Run, this)); m_Service.post (std::bind (&UPnP::Discover, this));
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
} }
UPnP::~UPnP () UPnP::~UPnP ()
{ {
Stop ();
} }
void UPnP::Run () void UPnP::Run ()
{ {
auto a = context.GetRouterInfo().GetAddresses(); while (m_IsRunning)
for (auto address : a)
{
if (!address->host.is_v6 ())
{ {
Discover (); try
if (address->transportStyle == data::RouterInfo::eTransportSSU )
{ {
TryPortMapping (I2P_UPNP_UDP, address->port); m_Service.run ();
} }
else if (address->transportStyle == data::RouterInfo::eTransportNTCP ) catch (std::exception& ex)
{ {
TryPortMapping (I2P_UPNP_TCP, address->port); LogPrint (eLogError, "UPnP: runtime exception: ", ex.what ());
}
} }
} }
} }
@ -87,37 +92,58 @@ namespace transport
} }
else else
{ {
if (m_externalIPAddress[0]) if (!m_externalIPAddress[0])
{ {
LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress); LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed.");
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
return; return;
}
}
} }
else else
{ {
LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed."); LogPrint (eLogError, "UPnP: GetValidIGD() failed.");
return; return;
} }
// UPnP discovered
LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
// port mapping
PortMapping ();
} }
void UPnP::PortMapping ()
{
auto a = context.GetRouterInfo().GetAddresses();
for (auto address : a)
{
if (!address->host.is_v6 ())
TryPortMapping (address);
} }
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
PortMapping ();
});
} }
void UPnP::TryPortMapping (int type, int port) void UPnP::CloseMapping ()
{ {
std::string strType, strPort (std::to_string (port)); auto a = context.GetRouterInfo().GetAddresses();
switch (type) for (auto address : a)
{ {
case I2P_UPNP_TCP: if (!address->host.is_v6 ())
strType = "TCP"; CloseMapping (address);
break; }
case I2P_UPNP_UDP:
default:
strType = "UDP";
} }
void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int r; int r;
std::string strDesc = "I2Pd"; std::string strDesc = "I2Pd";
try {
for (;;) {
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
if (r!=UPNPCOMMAND_SUCCESS) if (r!=UPNPCOMMAND_SUCCESS)
{ {
@ -129,31 +155,11 @@ namespace transport
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")"); LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")");
return; return;
} }
std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11
//boost::this_thread::sleep_for(); // pre c++11
//sleep(20*60); // non-portable
}
}
catch (boost::thread_interrupted)
{
CloseMapping(type, port);
Close();
throw;
}
} }
void UPnP::CloseMapping (int type, int port) void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{
std::string strType, strPort (std::to_string (port));
switch (type)
{ {
case I2P_UPNP_TCP: std::string strType (GetProto (address)), strPort (std::to_string (address->port));
strType = "TCP";
break;
case I2P_UPNP_UDP:
default:
strType = "UDP";
}
int r = 0; int r = 0;
r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0); r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r);
@ -165,6 +171,19 @@ namespace transport
m_Devlist = 0; m_Devlist = 0;
FreeUPNPUrls (&m_upnpUrls); FreeUPNPUrls (&m_upnpUrls);
} }
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{
switch (address->transportStyle)
{
case i2p::data::RouterInfo::eTransportNTCP:
return "TCP";
break;
case i2p::data::RouterInfo::eTransportSSU:
default:
return "UDP";
}
}
} }
} }
#else /* USE_UPNP */ #else /* USE_UPNP */

22
UPnP.h

@ -4,6 +4,7 @@
#ifdef USE_UPNP #ifdef USE_UPNP
#include <string> #include <string>
#include <thread> #include <thread>
#include <memory>
#include <miniupnpc/miniwget.h> #include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
@ -14,9 +15,6 @@
#include "util.h" #include "util.h"
#define I2P_UPNP_TCP 1
#define I2P_UPNP_UDP 2
namespace i2p namespace i2p
{ {
namespace transport namespace transport
@ -32,13 +30,23 @@ namespace transport
void Start (); void Start ();
void Stop (); void Stop ();
void Discover ();
void TryPortMapping (int type, int port);
void CloseMapping (int type, int port);
private: private:
void Discover ();
void PortMapping ();
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void CloseMapping ();
void CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void Run (); void Run ();
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
private:
std::thread * m_Thread; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer;
struct UPNPUrls m_upnpUrls; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData; struct IGDdatas m_upnpData;

Loading…
Cancel
Save