blob: 17300dcfefa7788881a189e456539783a5f2ad14 [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}
45
46/**
47 * A PeerConnectionRequest is a request which ask for an initial connection
48 * It contains the ICE request an ID and if it's an answer
49 * Transmitted via the UDP DHT
50 */
51struct PeerConnectionRequest : public dht::EncryptedValue<PeerConnectionRequest>
52{
53 static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA;
54 static constexpr const char* key_prefix = "peer:"; ///< base to compute the DHT listen key
55 dht::Value::Id id = dht::Value::INVALID_ID;
56 std::string ice_msg {};
57 bool isAnswer {false};
58 std::string connType {}; // Used for push notifications to know why we open a new connection
59 MSGPACK_DEFINE_MAP(id, ice_msg, isAnswer, connType)
60};
61
62/**
63 * Used to accept or not an incoming ICE connection (default accept)
64 */
65using onICERequestCallback = std::function<bool(const DeviceId&)>;
66/**
67 * Used to accept or decline an incoming channel request
68 */
69using ChannelRequestCallback = std::function<bool(const std::shared_ptr<dht::crypto::Certificate>&,
70 const std::string& /* name */)>;
71/**
72 * Used by connectDevice, when the socket is ready
73 */
74using ConnectCallback = std::function<void(const std::shared_ptr<ChannelSocket>&, const DeviceId&)>;
Amna0cf544d2023-07-25 14:25:09 -040075using ConnectCallbackLegacy = std::function<void(const std::shared_ptr<ChannelSocket>&, const dht::InfoHash&)>;
76
Adrien Béraud612b55b2023-05-29 10:42:04 -040077/**
78 * Used when an incoming connection is ready
79 */
80using ConnectionReadyCallback = std::function<
81 void(const DeviceId&, const std::string& /* channel_name */, std::shared_ptr<ChannelSocket>)>;
82
83using iOSConnectedCallback
84 = std::function<bool(const std::string& /* connType */, dht::InfoHash /* peer_h */)>;
85
86/**
87 * Manages connections to other devices
88 * @note the account MUST be valid if ConnectionManager lives
89 */
90class ConnectionManager
91{
92public:
Adrien Béraudc8cd2c72023-07-21 13:15:58 -040093 struct Config;
Adrien Béraud612b55b2023-05-29 10:42:04 -040094
95 ConnectionManager(std::shared_ptr<Config> config_);
96 ~ConnectionManager();
97
98 /**
99 * Open a new channel between the account's device and another device
100 * This method will send a message on the account's DHT, wait a reply
101 * and then, create a Tls socket with remote peer.
102 * @param deviceId Remote device
103 * @param name Name of the channel
104 * @param cb Callback called when socket is ready ready
105 * @param noNewSocket Do not negotiate a new socket if there is none
106 * @param forceNewSocket Negotiate a new socket even if there is one // todo group with previous
107 * (enum)
108 * @param connType Type of the connection
109 */
110 void connectDevice(const DeviceId& deviceId,
111 const std::string& name,
112 ConnectCallback cb,
113 bool noNewSocket = false,
114 bool forceNewSocket = false,
115 const std::string& connType = "");
Amna0cf544d2023-07-25 14:25:09 -0400116 void connectDevice(const dht::InfoHash& deviceId,
117 const std::string& name,
118 ConnectCallbackLegacy cb,
119 bool noNewSocket = false,
120 bool forceNewSocket = false,
121 const std::string& connType = "");
122
Adrien Béraud612b55b2023-05-29 10:42:04 -0400123 void connectDevice(const std::shared_ptr<dht::crypto::Certificate>& cert,
124 const std::string& name,
125 ConnectCallback cb,
126 bool noNewSocket = false,
127 bool forceNewSocket = false,
128 const std::string& connType = "");
129
130 /**
131 * Check if we are already connecting to a device with a specific name
132 * @param deviceId Remote device
133 * @param name Name of the channel
134 * @return if connecting
135 * @note isConnecting is not true just after connectDevice() as connectDevice is full async
136 */
137 bool isConnecting(const DeviceId& deviceId, const std::string& name) const;
138
139 /**
140 * Close all connections with a current device
141 * @param peerUri Peer URI
142 */
143 void closeConnectionsWith(const std::string& peerUri);
144
145 /**
146 * Method to call to listen to incoming requests
147 * @param deviceId Account's device
148 */
149 void onDhtConnected(const dht::crypto::PublicKey& devicePk);
150
151 /**
152 * Add a callback to decline or accept incoming ICE connections
153 * @param cb Callback to trigger
154 */
155 void onICERequest(onICERequestCallback&& cb);
156
157 /**
158 * Trigger cb on incoming peer channel
159 * @param cb Callback to trigger
160 * @note The callback is used to validate
161 * if the incoming request is accepted or not.
162 */
163 void onChannelRequest(ChannelRequestCallback&& cb);
164
165 /**
166 * Trigger cb when connection with peer is ready
167 * @param cb Callback to trigger
168 */
169 void onConnectionReady(ConnectionReadyCallback&& cb);
170
171 /**
172 * Trigger cb when connection with peer is ready for iOS devices
173 * @param cb Callback to trigger
174 */
175 void oniOSConnected(iOSConnectedCallback&& cb);
176
177 /**
178 * @return the number of active sockets
179 */
180 std::size_t activeSockets() const;
181
182 /**
183 * Log informations for all sockets
184 */
185 void monitor() const;
186
187 /**
188 * Send beacon on peers supporting it
189 */
190 void connectivityChanged();
191
192 /**
193 * Create and return ICE options.
194 */
195 void getIceOptions(std::function<void(IceTransportOptions&&)> cb) noexcept;
196 IceTransportOptions getIceOptions() const noexcept;
197
198 /**
199 * Get the published IP address, fallbacks to NAT if family is unspecified
200 * Prefers the usage of IPv4 if possible.
201 */
202 IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const;
203
204 /**
205 * Set published IP address according to given family
206 */
207 void setPublishedAddress(const IpAddr& ip_addr);
208
209 /**
210 * Store the local/public addresses used to register
211 */
212 void storeActiveIpAddress(std::function<void()>&& cb = {});
213
214 std::shared_ptr<Config> getConfig();
215
216private:
217 ConnectionManager() = delete;
218 class Impl;
219 std::shared_ptr<Impl> pimpl_;
220};
221
222struct ConnectionManager::Config
223{
224 /**
225 * Determine if STUN public address resolution is required to register this account. In this
226 * case a STUN server hostname must be specified.
227 */
228 bool stunEnabled {false};
229
230 /**
231 * The STUN server hostname (optional), used to provide the public IP address in case the
232 * softphone stay behind a NAT.
233 */
234 std::string stunServer {};
235
236 /**
237 * Determine if TURN public address resolution is required to register this account. In this
238 * case a TURN server hostname must be specified.
239 */
240 bool turnEnabled {false};
241
242 /**
243 * The TURN server hostname (optional), used to provide the public IP address in case the
244 * softphone stay behind a NAT.
245 */
246 std::string turnServer;
247 std::string turnServerUserName;
248 std::string turnServerPwd;
249 std::string turnServerRealm;
250
Sébastien Blin84bf4182023-07-21 14:18:39 -0400251 std::shared_ptr<TurnCache> turnCache;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400252
253 std::string cachePath {};
254
255 std::shared_ptr<asio::io_context> ioContext;
256 std::shared_ptr<dht::DhtRunner> dht;
257 dht::crypto::Identity id;
258
259 tls::CertificateStore* certStore;
260
Sébastien Blin34086512023-07-25 09:52:14 -0400261 dhtnet::IceTransportFactory* factory;
262
Adrien Béraud612b55b2023-05-29 10:42:04 -0400263 /**
264 * UPnP IGD controller and the mutex to access it
Sébastien Blin464bdff2023-07-19 08:02:53 -0400265 */
Adrien Béraud612b55b2023-05-29 10:42:04 -0400266 bool upnpEnabled;
Adrien Béraud1ae60aa2023-07-07 09:55:09 -0400267 std::shared_ptr<dhtnet::upnp::Controller> upnpCtrl;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400268
269 std::shared_ptr<dht::log::Logger> logger;
270
271 /**
272 * returns whether or not UPnP is enabled and active
273 * ie: if it is able to make port mappings
274 */
275 bool getUPnPActive() const;
276};
277
Sébastien Blin464bdff2023-07-19 08:02:53 -0400278} // namespace dhtnet