blob: 77db1cefe3247cb0601b59487cc6693f54afb43f [file] [log] [blame]
/*
* Copyright (C) 2004-2023 Savoir-faire Linux Inc.
*
* This program 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.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "upnp/upnp_control.h"
#include "upnp/upnp_context.h"
namespace dhtnet {
namespace upnp {
Controller::Controller(const std::shared_ptr<UPnPContext>& ctx)
: upnpContext_(ctx)
{
upnpContext_->registerController(this);
// JAMI_DBG("Controller@%p: Created UPnP Controller session", this);
}
Controller::~Controller()
{
// JAMI_DBG("Controller@%p: Destroying UPnP Controller session", this);
releaseAllMappings();
upnpContext_->unregisterController(this);
}
void
Controller::setPublicAddress(const IpAddr& addr)
{
assert(upnpContext_);
if (addr and addr.getFamily() == AF_INET) {
upnpContext_->setPublicAddress(addr);
}
}
bool
Controller::isReady() const
{
assert(upnpContext_);
return upnpContext_->isReady();
}
IpAddr
Controller::getExternalIP() const
{
assert(upnpContext_);
if (upnpContext_->isReady()) {
return upnpContext_->getExternalIP();
}
return {};
}
Mapping::sharedPtr_t
Controller::reserveMapping(uint16_t port, PortType type)
{
Mapping map(type, port, port);
return reserveMapping(map);
}
Mapping::sharedPtr_t
Controller::reserveMapping(Mapping& requestedMap)
{
assert(upnpContext_);
// Try to get a provisioned port
auto mapRes = upnpContext_->reserveMapping(requestedMap);
if (mapRes)
addLocalMap(*mapRes);
return mapRes;
}
void
Controller::releaseMapping(const Mapping& map)
{
assert(upnpContext_);
removeLocalMap(map);
return upnpContext_->releaseMapping(map);
}
void
Controller::releaseAllMappings()
{
assert(upnpContext_);
std::lock_guard<std::mutex> lk(mapListMutex_);
for (auto const& [_, map] : mappingList_) {
upnpContext_->releaseMapping(map);
}
mappingList_.clear();
}
void
Controller::addLocalMap(const Mapping& map)
{
if (map.getMapKey()) {
std::lock_guard<std::mutex> lock(mapListMutex_);
auto ret = mappingList_.emplace(map.getMapKey(), map);
if (not ret.second) {
// JAMI_WARN("Mapping request for %s already in the list!", map.toString().c_str());
}
}
}
bool
Controller::removeLocalMap(const Mapping& map)
{
assert(upnpContext_);
std::lock_guard<std::mutex> lk(mapListMutex_);
if (mappingList_.erase(map.getMapKey()) != 1) {
// JAMI_ERR("Failed to remove mapping %s from local list", map.getTypeStr());
return false;
}
return true;
}
uint16_t
Controller::generateRandomPort(PortType type)
{
return UPnPContext::generateRandomPort(type);
}
} // namespace upnp
} // namespace jami