blob: 086981f6825487729a44d03c46e546d375cff1a4 [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraud612b55b2023-05-29 10:42:04 -04005 * it under the terms of the GNU General Public License as published by
Adrien Béraudcb753622023-07-17 22:32:49 -04006 * the Free Software Foundation, either version 3 of the License, or
Adrien Béraud612b55b2023-05-29 10:42:04 -04007 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Adrien Béraudcb753622023-07-17 22:32:49 -040011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Adrien Béraud612b55b2023-05-29 10:42:04 -040012 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include "ice_options.h"
20#include "multiplexed_socket.h"
Sébastien Blin34086512023-07-25 09:52:14 -040021#include "ice_transport_factory.h"
Sébastien Blin84bf4182023-07-21 14:18:39 -040022#include "turn_cache.h"
Adrien Béraud612b55b2023-05-29 10:42:04 -040023
24#include <opendht/dhtrunner.h>
25#include <opendht/infohash.h>
26#include <opendht/value.h>
27#include <opendht/default_types.h>
28#include <opendht/sockaddr.h>
29#include <opendht/logger.h>
30
31#include <memory>
32#include <vector>
33#include <string>
34
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040035namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040036
37class ChannelSocket;
38class ConnectionManager;
39namespace upnp {
40class Controller;
41}
42namespace tls {
43class CertificateStore;
44}
Amna31791e52023-08-03 12:40:57 -040045enum class ConnectionStatus : int { Connected, TLS, ICE, Connecting, Waiting };
Adrien Béraud612b55b2023-05-29 10:42:04 -040046
47/**
48 * A PeerConnectionRequest is a request which ask for an initial connection
49 * It contains the ICE request an ID and if it's an answer
50 * Transmitted via the UDP DHT
51 */
52struct PeerConnectionRequest : public dht::EncryptedValue<PeerConnectionRequest>
53{
54 static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA;
55 static constexpr const char* key_prefix = "peer:"; ///< base to compute the DHT listen key
56 dht::Value::Id id = dht::Value::INVALID_ID;
57 std::string ice_msg {};
58 bool isAnswer {false};
59 std::string connType {}; // Used for push notifications to know why we open a new connection
60 MSGPACK_DEFINE_MAP(id, ice_msg, isAnswer, connType)
61};
62
63/**
64 * Used to accept or not an incoming ICE connection (default accept)
65 */
66using onICERequestCallback = std::function<bool(const DeviceId&)>;
67/**
68 * Used to accept or decline an incoming channel request
69 */
70using ChannelRequestCallback = std::function<bool(const std::shared_ptr<dht::crypto::Certificate>&,
71 const std::string& /* name */)>;
72/**
73 * Used by connectDevice, when the socket is ready
74 */
75using ConnectCallback = std::function<void(const std::shared_ptr<ChannelSocket>&, const DeviceId&)>;
Amna0cf544d2023-07-25 14:25:09 -040076using ConnectCallbackLegacy = std::function<void(const std::shared_ptr<ChannelSocket>&, const dht::InfoHash&)>;
77
Adrien Béraud612b55b2023-05-29 10:42:04 -040078/**
79 * Used when an incoming connection is ready
80 */
81using ConnectionReadyCallback = std::function<
82 void(const DeviceId&, const std::string& /* channel_name */, std::shared_ptr<ChannelSocket>)>;
83
84using iOSConnectedCallback
85 = std::function<bool(const std::string& /* connType */, dht::InfoHash /* peer_h */)>;
86
87/**
88 * Manages connections to other devices
89 * @note the account MUST be valid if ConnectionManager lives
90 */
91class ConnectionManager
92{
93public:
Adrien Béraudc8cd2c72023-07-21 13:15:58 -040094 struct Config;
Adrien Béraud612b55b2023-05-29 10:42:04 -040095
96 ConnectionManager(std::shared_ptr<Config> config_);
Amna81221ad2023-09-14 17:33:26 -040097 ConnectionManager(dht::crypto::Identity id);
98
Adrien Béraud612b55b2023-05-29 10:42:04 -040099 ~ConnectionManager();
100
101 /**
102 * Open a new channel between the account's device and another device
103 * This method will send a message on the account's DHT, wait a reply
104 * and then, create a Tls socket with remote peer.
105 * @param deviceId Remote device
106 * @param name Name of the channel
107 * @param cb Callback called when socket is ready ready
108 * @param noNewSocket Do not negotiate a new socket if there is none
109 * @param forceNewSocket Negotiate a new socket even if there is one // todo group with previous
110 * (enum)
111 * @param connType Type of the connection
112 */
113 void connectDevice(const DeviceId& deviceId,
114 const std::string& name,
115 ConnectCallback cb,
116 bool noNewSocket = false,
117 bool forceNewSocket = false,
118 const std::string& connType = "");
Amna0cf544d2023-07-25 14:25:09 -0400119 void connectDevice(const dht::InfoHash& deviceId,
120 const std::string& name,
121 ConnectCallbackLegacy cb,
122 bool noNewSocket = false,
123 bool forceNewSocket = false,
124 const std::string& connType = "");
125
Adrien Béraud612b55b2023-05-29 10:42:04 -0400126 void connectDevice(const std::shared_ptr<dht::crypto::Certificate>& cert,
127 const std::string& name,
128 ConnectCallback cb,
129 bool noNewSocket = false,
130 bool forceNewSocket = false,
131 const std::string& connType = "");
132
133 /**
134 * Check if we are already connecting to a device with a specific name
135 * @param deviceId Remote device
136 * @param name Name of the channel
137 * @return if connecting
138 * @note isConnecting is not true just after connectDevice() as connectDevice is full async
139 */
140 bool isConnecting(const DeviceId& deviceId, const std::string& name) const;
141
142 /**
Sébastien Blind0c92c72023-12-07 15:27:51 -0500143 * Check if we are already connected to a device
144 * @param deviceId Remote device
145 * @return if connected
146 */
147 bool isConnected(const DeviceId& deviceId) const;
148
149 /**
Adrien Béraud612b55b2023-05-29 10:42:04 -0400150 * Close all connections with a current device
151 * @param peerUri Peer URI
152 */
153 void closeConnectionsWith(const std::string& peerUri);
154
155 /**
156 * Method to call to listen to incoming requests
157 * @param deviceId Account's device
158 */
159 void onDhtConnected(const dht::crypto::PublicKey& devicePk);
160
161 /**
162 * Add a callback to decline or accept incoming ICE connections
163 * @param cb Callback to trigger
164 */
165 void onICERequest(onICERequestCallback&& cb);
166
167 /**
168 * Trigger cb on incoming peer channel
169 * @param cb Callback to trigger
170 * @note The callback is used to validate
171 * if the incoming request is accepted or not.
172 */
173 void onChannelRequest(ChannelRequestCallback&& cb);
174
175 /**
176 * Trigger cb when connection with peer is ready
177 * @param cb Callback to trigger
178 */
179 void onConnectionReady(ConnectionReadyCallback&& cb);
180
181 /**
182 * Trigger cb when connection with peer is ready for iOS devices
183 * @param cb Callback to trigger
184 */
185 void oniOSConnected(iOSConnectedCallback&& cb);
186
187 /**
188 * @return the number of active sockets
189 */
190 std::size_t activeSockets() const;
191
192 /**
193 * Log informations for all sockets
194 */
195 void monitor() const;
196
197 /**
198 * Send beacon on peers supporting it
199 */
200 void connectivityChanged();
201
202 /**
203 * Create and return ICE options.
204 */
205 void getIceOptions(std::function<void(IceTransportOptions&&)> cb) noexcept;
206 IceTransportOptions getIceOptions() const noexcept;
207
208 /**
209 * Get the published IP address, fallbacks to NAT if family is unspecified
210 * Prefers the usage of IPv4 if possible.
211 */
212 IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const;
213
214 /**
215 * Set published IP address according to given family
216 */
217 void setPublishedAddress(const IpAddr& ip_addr);
218
219 /**
220 * Store the local/public addresses used to register
221 */
222 void storeActiveIpAddress(std::function<void()>&& cb = {});
223
Amna31791e52023-08-03 12:40:57 -0400224 /**
225 * Retrieve the list of connections.
226 *
227 * @param device The device ID to filter the connections (optional).
228 * @return The list of connections as a vector of maps, where each map represents a connection.
229 *
230 * Note: The connections are represented as maps with string keys and string values. The map
231 * contains the following key-value pairs:
232 * - "id": The unique identifier of the connection.
Amna6c999d82023-08-15 15:19:41 -0400233 * - "device": The device URI associated with the connection.
Amna31791e52023-08-03 12:40:57 -0400234 * - "status": The status of the connection, represented as an integer:
235 * - 0: ConnectionStatus::Connected
236 * - 1: ConnectionStatus::TLS
237 * - 2: ConnectionStatus::ICE
238 * - 3: ConnectionStatus::Connecting (for pending operations)
239 * - 4: ConnectionStatus::Waiting (for pending operations)
240 * - "remoteAddress": The remote IP address of the connection (if available).
241 * - "remotePort": The remote port of the connection (if available).
242 *
243 * If a specific device ID is provided, the returned list will only include connections
244 * associated with that device. Otherwise, connections from all devices will be included.
245 */
246 std::vector<std::map<std::string, std::string>> getConnectionList(
247 const DeviceId& device = {}) const;
248
249 /**
250 * Retrieve the list of channels associated with a connection.
251 *
252 * @param connectionId The ID of the connection to fetch the channels from.
253 * @return The list of channels as a vector of maps, where each map represents a channel
254 * and contains key-value pairs of channel ID and channel name.
255 *
256 * If the specified connection ID is valid and associated with a connection,
257 * the method returns the list of channels associated with that connection.
258 * Otherwise, an empty vector is returned.
259 */
260 std::vector<std::map<std::string, std::string>> getChannelList(
261 const std::string& connectionId) const;
262
263
Adrien Béraud612b55b2023-05-29 10:42:04 -0400264 std::shared_ptr<Config> getConfig();
265
266private:
267 ConnectionManager() = delete;
268 class Impl;
269 std::shared_ptr<Impl> pimpl_;
270};
271
272struct ConnectionManager::Config
273{
274 /**
275 * Determine if STUN public address resolution is required to register this account. In this
276 * case a STUN server hostname must be specified.
277 */
278 bool stunEnabled {false};
279
280 /**
281 * The STUN server hostname (optional), used to provide the public IP address in case the
282 * softphone stay behind a NAT.
283 */
284 std::string stunServer {};
285
286 /**
287 * Determine if TURN public address resolution is required to register this account. In this
288 * case a TURN server hostname must be specified.
289 */
290 bool turnEnabled {false};
291
292 /**
293 * The TURN server hostname (optional), used to provide the public IP address in case the
294 * softphone stay behind a NAT.
295 */
296 std::string turnServer;
297 std::string turnServerUserName;
298 std::string turnServerPwd;
299 std::string turnServerRealm;
300
Sébastien Blin84bf4182023-07-21 14:18:39 -0400301 std::shared_ptr<TurnCache> turnCache;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400302
Adrien Béraud2a4e73d2023-08-27 12:53:55 -0400303 std::filesystem::path cachePath {};
Adrien Béraud612b55b2023-05-29 10:42:04 -0400304 std::shared_ptr<asio::io_context> ioContext;
305 std::shared_ptr<dht::DhtRunner> dht;
Amna81221ad2023-09-14 17:33:26 -0400306 dht::crypto::Identity id {};
Adrien Béraud612b55b2023-05-29 10:42:04 -0400307
Amna81221ad2023-09-14 17:33:26 -0400308 std::shared_ptr<tls::CertificateStore> certStore {nullptr};
309 std::shared_ptr<dhtnet::IceTransportFactory> factory {nullptr};
Sébastien Blin34086512023-07-25 09:52:14 -0400310
Adrien Béraud612b55b2023-05-29 10:42:04 -0400311 /**
312 * UPnP IGD controller and the mutex to access it
Sébastien Blin464bdff2023-07-19 08:02:53 -0400313 */
Amna81221ad2023-09-14 17:33:26 -0400314 bool upnpEnabled {true};
Adrien Béraud1ae60aa2023-07-07 09:55:09 -0400315 std::shared_ptr<dhtnet::upnp::Controller> upnpCtrl;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400316 std::shared_ptr<dht::log::Logger> logger;
317
318 /**
319 * returns whether or not UPnP is enabled and active
320 * ie: if it is able to make port mappings
321 */
322 bool getUPnPActive() const;
Amna31791e52023-08-03 12:40:57 -0400323
Adrien Béraudd8b6a402023-12-08 14:19:25 -0500324 /** Optional pseudo random generator to be used, allowing to control the seed. */
325 std::unique_ptr<std::mt19937_64> rng;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400326};
327
Sébastien Blin464bdff2023-07-19 08:02:53 -0400328} // namespace dhtnet