add initial project structure

Change-Id: I6a3fb080ff623b312e42d71754480a7ce00b81a0
diff --git a/src/upnp/protocol/mapping.cpp b/src/upnp/protocol/mapping.cpp
new file mode 100644
index 0000000..9b38831
--- /dev/null
+++ b/src/upnp/protocol/mapping.cpp
@@ -0,0 +1,347 @@
+/*
+ *  Copyright (C) 2004-2023 Savoir-faire Linux Inc.
+ *
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *  Author: Eden Abitbol <eden.abitbol@savoirfairelinux.com>
+ *  Author: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com>
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "mapping.h"
+#include "logger.h"
+
+namespace jami {
+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 jami