/* * Copyright (c) 2011 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include namespace Swift { struct MiniUPnPInterface::Private { bool isValid; std::string localAddress; UPNPDev* deviceList; UPNPUrls urls; IGDdatas data; }; MiniUPnPInterface::MiniUPnPInterface() : p(boost::make_shared()) { p->isValid = false; int error = 0; p->deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); if (!p->deviceList) { return; } char lanAddress[64]; if (!UPNP_GetValidIGD(p->deviceList, &p->urls, &p->data, lanAddress, sizeof(lanAddress))) { return; } p->localAddress = std::string(lanAddress); p->isValid = true; } MiniUPnPInterface::~MiniUPnPInterface() { if (p->isValid) { FreeUPNPUrls(&p->urls); } freeUPNPDevlist(p->deviceList); } boost::optional MiniUPnPInterface::getPublicIP() { if (!p->isValid) { return boost::optional(); } char externalIPAddress[40]; int ret = UPNP_GetExternalIPAddress(p->urls.controlURL, p->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 (!p->isValid) { return boost::optional(); } NATPortMapping mapping(actualLocalPort, actualPublicPort, NATPortMapping::TCP); std::string publicPort = boost::lexical_cast(mapping.getPublicPort()); std::string localPort = boost::lexical_cast(mapping.getLocalPort()); std::string leaseSeconds = boost::lexical_cast(mapping.getLeaseInSeconds()); int ret = UPNP_AddPortMapping( p->urls.controlURL, p->data.first.servicetype, publicPort.c_str(), localPort.c_str(), p->localAddress.c_str(), "Swift", mapping.getProtocol() == 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 (!p->isValid) { return false; } std::string publicPort = boost::lexical_cast(mapping.getPublicPort()); std::string localPort = boost::lexical_cast(mapping.getLocalPort()); std::string leaseSeconds = boost::lexical_cast(mapping.getLeaseInSeconds()); int ret = UPNP_DeletePortMapping(p->urls.controlURL, p->data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", 0); return ret == UPNPCOMMAND_SUCCESS; } bool MiniUPnPInterface::isAvailable() { return p->isValid; } }