add turn cache

Change-Id: I71ed970e4005d73035223ac8b32c24b27e923f1e
diff --git a/include/turn_cache.h b/include/turn_cache.h
new file mode 100644
index 0000000..c8d3684
--- /dev/null
+++ b/include/turn_cache.h
@@ -0,0 +1,111 @@
+/*
+ *  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/>.
+ */
+#pragma once
+
+#include "ip_utils.h"
+#include "turn_params.h"
+
+#include <asio.hpp>
+
+#include <atomic>
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+
+namespace dht {
+namespace log {
+class Logger;
+}
+}
+
+namespace dhtnet {
+
+using Logger = dht::log::Logger;
+
+class TurnTransport;
+
+class TurnCache : public std::enable_shared_from_this<TurnCache>
+{
+public:
+    TurnCache(const std::string& accountId,
+              const std::string& cachePath,
+              const std::shared_ptr<asio::io_context>& io_context,
+              const std::shared_ptr<Logger>& logger,
+              const TurnTransportParams& params,
+              bool enabled);
+    ~TurnCache();
+
+    std::optional<IpAddr> getResolvedTurn(uint16_t family = AF_INET) const;
+    /**
+     * Pass a new configuration for the cache
+     * @param param     The new configuration
+     */
+    void reconfigure(const TurnTransportParams& params, bool enabled);
+    /**
+     * Refresh cache from current configuration
+     */
+    void refresh(const asio::error_code& ec = {});
+
+private:
+    std::string accountId_;
+    std::string cachePath_;
+    TurnTransportParams params_;
+    std::atomic_bool enabled_ {false};
+    /**
+     * Avoid to refresh the cache multiple times
+     */
+    std::atomic_bool isRefreshing_ {false};
+    /**
+     * This will cache the turn server resolution each time we launch
+     * Jami, or for each connectivityChange()
+     */
+    void testTurn(IpAddr server);
+    std::unique_ptr<TurnTransport> testTurnV4_;
+    std::unique_ptr<TurnTransport> testTurnV6_;
+
+    // Used to detect if a turn server is down.
+    void refreshTurnDelay(bool scheduleNext);
+    std::chrono::seconds turnRefreshDelay_ {std::chrono::seconds(10)};
+
+    // Store resoved turn addresses
+    mutable std::mutex cachedTurnMutex_ {};
+    std::unique_ptr<IpAddr> cacheTurnV4_ {};
+    std::unique_ptr<IpAddr> cacheTurnV6_ {};
+
+    void onConnected(const asio::error_code& ec, bool ok, IpAddr server);
+
+    // io
+    std::shared_ptr<asio::io_context> io_context;
+    std::unique_ptr<asio::steady_timer> refreshTimer_;
+    std::unique_ptr<asio::steady_timer> onConnectedTimer_;
+
+    std::mutex shutdownMtx_;
+
+    std::shared_ptr<Logger> logger_;
+
+    // Asio :(
+    // https://stackoverflow.com/questions/35507956/is-it-safe-to-destroy-boostasio-timer-from-its-handler-or-handler-dtor
+    std::weak_ptr<TurnCache> weak()
+    {
+        return std::static_pointer_cast<TurnCache>(shared_from_this());
+    }
+};
+
+} // namespace jami