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