blob: 3aa24b345c6ed49ae0818c3caca18d4bc5e9bdcc [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/mapping.h"
// #include "logger.h"
#include "igd.h"
namespace dhtnet {
namespace upnp {
Mapping::Mapping(PortType type, uint16_t portExternal, uint16_t portInternal, bool available)
: type_(type)
, externalPort_(portExternal)
, internalPort_(portInternal)
, internalAddr_()
, igd_()
, available_(available)
, state_(MappingState::PENDING)
, notifyCb_(nullptr)
, autoUpdate_(false)
#if HAVE_LIBNATPMP
, renewalTime_(sys_clock::now())
#endif
{}
Mapping::Mapping(const Mapping& other)
{
std::lock_guard<std::mutex> lock(other.mutex_);
internalAddr_ = other.internalAddr_;
internalPort_ = other.internalPort_;
externalPort_ = other.externalPort_;
type_ = other.type_;
igd_ = other.igd_;
available_ = other.available_;
state_ = other.state_;
notifyCb_ = other.notifyCb_;
autoUpdate_ = other.autoUpdate_;
#if HAVE_LIBNATPMP
renewalTime_ = other.renewalTime_;
#endif
}
void
Mapping::updateFrom(const Mapping::sharedPtr_t& other)
{
updateFrom(*other);
}
void
Mapping::updateFrom(const Mapping& other)
{
if (type_ != other.type_) {
// JAMI_ERR("The source and destination types must match");
return;
}
internalAddr_ = std::move(other.internalAddr_);
internalPort_ = other.internalPort_;
externalPort_ = other.externalPort_;
igd_ = other.igd_;
state_ = other.state_;
}
void
Mapping::setAvailable(bool val)
{
// JAMI_DBG("Changing mapping %s state from %s to %s",
// toString().c_str(),
// available_ ? "AVAILABLE" : "UNAVAILABLE",
// val ? "AVAILABLE" : "UNAVAILABLE");
std::lock_guard<std::mutex> lock(mutex_);
available_ = val;
}
void
Mapping::setState(const MappingState& state)
{
std::lock_guard<std::mutex> lock(mutex_);
state_ = state;
}
const char*
Mapping::getStateStr() const
{
std::lock_guard<std::mutex> lock(mutex_);
return getStateStr(state_);
}
std::string
Mapping::toString(bool extraInfo) const
{
std::lock_guard<std::mutex> lock(mutex_);
std::ostringstream descr;
descr << UPNP_MAPPING_DESCRIPTION_PREFIX << "-" << getTypeStr(type_);
descr << ":" << std::to_string(internalPort_);
if (extraInfo) {
descr << " (state=" << getStateStr(state_)
<< ", auto-update=" << (autoUpdate_ ? "YES" : "NO") << ")";
}
return descr.str();
}
bool
Mapping::isValid() const
{
std::lock_guard<std::mutex> lock(mutex_);
if (state_ == MappingState::FAILED)
return false;
if (internalPort_ == 0)
return false;
if (externalPort_ == 0)
return false;
if (not igd_ or not igd_->isValid())
return false;
IpAddr intAddr(internalAddr_);
return intAddr and not intAddr.isLoopback();
}
bool
Mapping::hasValidHostAddress() const
{
std::lock_guard<std::mutex> lock(mutex_);
IpAddr intAddr(internalAddr_);
return intAddr and not intAddr.isLoopback();
}
bool
Mapping::hasPublicAddress() const
{
std::lock_guard<std::mutex> lock(mutex_);
return igd_ and igd_->getPublicIp() and not igd_->getPublicIp().isPrivate();
}
Mapping::key_t
Mapping::getMapKey() const
{
std::lock_guard<std::mutex> lock(mutex_);
key_t mapKey = internalPort_;
if (type_ == PortType::UDP)
mapKey |= 1 << (sizeof(uint16_t) * 8);
return mapKey;
}
PortType
Mapping::getTypeFromMapKey(key_t key)
{
return (key >> (sizeof(uint16_t) * 8)) ? PortType::UDP : PortType::TCP;
}
std::string
Mapping::getExternalAddress() const
{
std::lock_guard<std::mutex> lock(mutex_);
if (igd_)
return igd_->getPublicIp().toString();
return {};
}
void
Mapping::setExternalPort(uint16_t port)
{
std::lock_guard<std::mutex> lock(mutex_);
externalPort_ = port;
}
uint16_t
Mapping::getExternalPort() const
{
std::lock_guard<std::mutex> lock(mutex_);
return externalPort_;
}
std::string
Mapping::getExternalPortStr() const
{
std::lock_guard<std::mutex> lock(mutex_);
return std::to_string(externalPort_);
}
void
Mapping::setInternalAddress(const std::string& addr)
{
std::lock_guard<std::mutex> lock(mutex_);
internalAddr_ = addr;
}
std::string
Mapping::getInternalAddress() const
{
std::lock_guard<std::mutex> lock(mutex_);
return internalAddr_;
}
void
Mapping::setInternalPort(uint16_t port)
{
std::lock_guard<std::mutex> lock(mutex_);
internalPort_ = port;
}
uint16_t
Mapping::getInternalPort() const
{
std::lock_guard<std::mutex> lock(mutex_);
return internalPort_;
}
std::string
Mapping::getInternalPortStr() const
{
std::lock_guard<std::mutex> lock(mutex_);
return std::to_string(internalPort_);
}
PortType
Mapping::getType() const
{
std::lock_guard<std::mutex> lock(mutex_);
return type_;
}
const char*
Mapping::getTypeStr() const
{
std::lock_guard<std::mutex> lock(mutex_);
return getTypeStr(type_);
}
bool
Mapping::isAvailable() const
{
std::lock_guard<std::mutex> lock(mutex_);
return available_;
}
std::shared_ptr<IGD>
Mapping::getIgd() const
{
std::lock_guard<std::mutex> lock(mutex_);
return igd_;
}
NatProtocolType
Mapping::getProtocol() const
{
std::lock_guard<std::mutex> lock(mutex_);
if (igd_)
return igd_->getProtocol();
return NatProtocolType::UNKNOWN;
}
const char*
Mapping::getProtocolName() const
{
if (igd_) {
if (igd_->getProtocol() == NatProtocolType::NAT_PMP)
return "NAT-PMP";
if (igd_->getProtocol() == NatProtocolType::PUPNP)
return "PUPNP";
}
return "UNKNOWN";
}
void
Mapping::setIgd(const std::shared_ptr<IGD>& igd)
{
std::lock_guard<std::mutex> lock(mutex_);
igd_ = igd;
}
MappingState
Mapping::getState() const
{
std::lock_guard<std::mutex> lock(mutex_);
return state_;
}
Mapping::NotifyCallback
Mapping::getNotifyCallback() const
{
std::lock_guard<std::mutex> lock(mutex_);
return notifyCb_;
}
void
Mapping::setNotifyCallback(NotifyCallback cb)
{
std::lock_guard<std::mutex> lock(mutex_);
notifyCb_ = std::move(cb);
}
void
Mapping::enableAutoUpdate(bool enable)
{
std::lock_guard<std::mutex> lock(mutex_);
autoUpdate_ = enable;
}
bool
Mapping::getAutoUpdate() const
{
std::lock_guard<std::mutex> lock(mutex_);
return autoUpdate_;
}
#if HAVE_LIBNATPMP
sys_clock::time_point
Mapping::getRenewalTime() const
{
std::lock_guard<std::mutex> lock(mutex_);
return renewalTime_;
}
void
Mapping::setRenewalTime(sys_clock::time_point time)
{
std::lock_guard<std::mutex> lock(mutex_);
renewalTime_ = time;
}
#endif
} // namespace upnp
} // namespace dhtnet