| /* |
| * 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 "ice_options.h" |
| #include "multiplexed_socket.h" |
| |
| #include <opendht/dhtrunner.h> |
| #include <opendht/infohash.h> |
| #include <opendht/value.h> |
| #include <opendht/default_types.h> |
| #include <opendht/sockaddr.h> |
| #include <opendht/logger.h> |
| |
| #include <memory> |
| #include <vector> |
| #include <string> |
| |
| namespace jami { |
| |
| class ChannelSocket; |
| class ConnectionManager; |
| namespace upnp { |
| class Controller; |
| } |
| namespace tls { |
| class CertificateStore; |
| } |
| |
| /** |
| * A PeerConnectionRequest is a request which ask for an initial connection |
| * It contains the ICE request an ID and if it's an answer |
| * Transmitted via the UDP DHT |
| */ |
| struct PeerConnectionRequest : public dht::EncryptedValue<PeerConnectionRequest> |
| { |
| static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA; |
| static constexpr const char* key_prefix = "peer:"; ///< base to compute the DHT listen key |
| dht::Value::Id id = dht::Value::INVALID_ID; |
| std::string ice_msg {}; |
| bool isAnswer {false}; |
| std::string connType {}; // Used for push notifications to know why we open a new connection |
| MSGPACK_DEFINE_MAP(id, ice_msg, isAnswer, connType) |
| }; |
| |
| /** |
| * Used to accept or not an incoming ICE connection (default accept) |
| */ |
| using onICERequestCallback = std::function<bool(const DeviceId&)>; |
| /** |
| * Used to accept or decline an incoming channel request |
| */ |
| using ChannelRequestCallback = std::function<bool(const std::shared_ptr<dht::crypto::Certificate>&, |
| const std::string& /* name */)>; |
| /** |
| * Used by connectDevice, when the socket is ready |
| */ |
| using ConnectCallback = std::function<void(const std::shared_ptr<ChannelSocket>&, const DeviceId&)>; |
| /** |
| * Used when an incoming connection is ready |
| */ |
| using ConnectionReadyCallback = std::function< |
| void(const DeviceId&, const std::string& /* channel_name */, std::shared_ptr<ChannelSocket>)>; |
| |
| using iOSConnectedCallback |
| = std::function<bool(const std::string& /* connType */, dht::InfoHash /* peer_h */)>; |
| |
| /** |
| * Manages connections to other devices |
| * @note the account MUST be valid if ConnectionManager lives |
| */ |
| class ConnectionManager |
| { |
| public: |
| class Config; |
| |
| ConnectionManager(std::shared_ptr<Config> config_); |
| ~ConnectionManager(); |
| |
| /** |
| * Open a new channel between the account's device and another device |
| * This method will send a message on the account's DHT, wait a reply |
| * and then, create a Tls socket with remote peer. |
| * @param deviceId Remote device |
| * @param name Name of the channel |
| * @param cb Callback called when socket is ready ready |
| * @param noNewSocket Do not negotiate a new socket if there is none |
| * @param forceNewSocket Negotiate a new socket even if there is one // todo group with previous |
| * (enum) |
| * @param connType Type of the connection |
| */ |
| void connectDevice(const DeviceId& deviceId, |
| const std::string& name, |
| ConnectCallback cb, |
| bool noNewSocket = false, |
| bool forceNewSocket = false, |
| const std::string& connType = ""); |
| void connectDevice(const std::shared_ptr<dht::crypto::Certificate>& cert, |
| const std::string& name, |
| ConnectCallback cb, |
| bool noNewSocket = false, |
| bool forceNewSocket = false, |
| const std::string& connType = ""); |
| |
| /** |
| * Check if we are already connecting to a device with a specific name |
| * @param deviceId Remote device |
| * @param name Name of the channel |
| * @return if connecting |
| * @note isConnecting is not true just after connectDevice() as connectDevice is full async |
| */ |
| bool isConnecting(const DeviceId& deviceId, const std::string& name) const; |
| |
| /** |
| * Close all connections with a current device |
| * @param peerUri Peer URI |
| */ |
| void closeConnectionsWith(const std::string& peerUri); |
| |
| /** |
| * Method to call to listen to incoming requests |
| * @param deviceId Account's device |
| */ |
| void onDhtConnected(const dht::crypto::PublicKey& devicePk); |
| |
| /** |
| * Add a callback to decline or accept incoming ICE connections |
| * @param cb Callback to trigger |
| */ |
| void onICERequest(onICERequestCallback&& cb); |
| |
| /** |
| * Trigger cb on incoming peer channel |
| * @param cb Callback to trigger |
| * @note The callback is used to validate |
| * if the incoming request is accepted or not. |
| */ |
| void onChannelRequest(ChannelRequestCallback&& cb); |
| |
| /** |
| * Trigger cb when connection with peer is ready |
| * @param cb Callback to trigger |
| */ |
| void onConnectionReady(ConnectionReadyCallback&& cb); |
| |
| /** |
| * Trigger cb when connection with peer is ready for iOS devices |
| * @param cb Callback to trigger |
| */ |
| void oniOSConnected(iOSConnectedCallback&& cb); |
| |
| /** |
| * @return the number of active sockets |
| */ |
| std::size_t activeSockets() const; |
| |
| /** |
| * Log informations for all sockets |
| */ |
| void monitor() const; |
| |
| /** |
| * Send beacon on peers supporting it |
| */ |
| void connectivityChanged(); |
| |
| /** |
| * Create and return ICE options. |
| */ |
| void getIceOptions(std::function<void(IceTransportOptions&&)> cb) noexcept; |
| IceTransportOptions getIceOptions() const noexcept; |
| |
| /** |
| * Get the published IP address, fallbacks to NAT if family is unspecified |
| * Prefers the usage of IPv4 if possible. |
| */ |
| IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const; |
| |
| /** |
| * Set published IP address according to given family |
| */ |
| void setPublishedAddress(const IpAddr& ip_addr); |
| |
| /** |
| * Store the local/public addresses used to register |
| */ |
| void storeActiveIpAddress(std::function<void()>&& cb = {}); |
| |
| std::shared_ptr<Config> getConfig(); |
| |
| private: |
| ConnectionManager() = delete; |
| class Impl; |
| std::shared_ptr<Impl> pimpl_; |
| }; |
| |
| struct ConnectionManager::Config |
| { |
| /** |
| * Determine if STUN public address resolution is required to register this account. In this |
| * case a STUN server hostname must be specified. |
| */ |
| bool stunEnabled {false}; |
| |
| /** |
| * The STUN server hostname (optional), used to provide the public IP address in case the |
| * softphone stay behind a NAT. |
| */ |
| std::string stunServer {}; |
| |
| /** |
| * Determine if TURN public address resolution is required to register this account. In this |
| * case a TURN server hostname must be specified. |
| */ |
| bool turnEnabled {false}; |
| |
| /** |
| * The TURN server hostname (optional), used to provide the public IP address in case the |
| * softphone stay behind a NAT. |
| */ |
| std::string turnServer; |
| std::string turnServerUserName; |
| std::string turnServerPwd; |
| std::string turnServerRealm; |
| |
| mutable std::mutex cachedTurnMutex {}; |
| dht::SockAddr cacheTurnV4 {}; |
| dht::SockAddr cacheTurnV6 {}; |
| |
| std::string cachePath {}; |
| |
| std::shared_ptr<asio::io_context> ioContext; |
| std::shared_ptr<dht::DhtRunner> dht; |
| dht::crypto::Identity id; |
| |
| tls::CertificateStore* certStore; |
| |
| /** |
| * UPnP IGD controller and the mutex to access it |
| */ |
| bool upnpEnabled; |
| std::shared_ptr<jami::upnp::Controller> upnpCtrl; |
| |
| std::shared_ptr<dht::log::Logger> logger; |
| |
| /** |
| * returns whether or not UPnP is enabled and active |
| * ie: if it is able to make port mappings |
| */ |
| bool getUPnPActive() const; |
| }; |
| |
| } // namespace jami |