blob: 83914425824be5b2b31ddc0785b008761ffcfdfa [file] [log] [blame]
Adrien Béraudefe27372023-05-27 18:56:29 -04001/*
Adrien Béraudcb753622023-07-17 22:32:49 -04002 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
Adrien Béraudefe27372023-05-27 18:56:29 -04003 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraudefe27372023-05-27 18:56:29 -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éraudefe27372023-05-27 18:56:29 -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éraudefe27372023-05-27 18:56:29 -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 */
Adrien Béraudefe27372023-05-27 18:56:29 -040017
18#include "connectionmanager.h"
19#include "multiplexed_socket.h"
20#include "test_runner.h"
Morteza Namvar82960b32023-07-04 17:08:22 -040021#include "certstore.h"
Adrien Béraudefe27372023-05-27 18:56:29 -040022
Adrien Béraud027af2a2023-08-27 12:08:50 -040023#include <opendht/log.h>
24#include <asio/executor_work_guard.hpp>
25#include <asio/io_context.hpp>
Adrien Béraud75754b22023-10-17 09:16:06 -040026#include <fmt/compile.h>
Adrien Béraud027af2a2023-08-27 12:08:50 -040027
28#include <cppunit/TestAssert.h>
29#include <cppunit/TestFixture.h>
30#include <cppunit/extensions/HelperMacros.h>
31
32#include <condition_variable>
33#include <iostream>
34#include <filesystem>
35
Adrien Béraudefe27372023-05-27 18:56:29 -040036using namespace std::literals::chrono_literals;
37
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040038namespace dhtnet {
Adrien Béraudefe27372023-05-27 18:56:29 -040039namespace test {
40
Amnab8c33bb2023-08-03 14:40:01 -040041struct ConnectionHandler
42{
Morteza Namvar82960b32023-07-04 17:08:22 -040043 dht::crypto::Identity id;
44 std::shared_ptr<Logger> logger;
45 std::shared_ptr<tls::CertificateStore> certStore;
46 std::shared_ptr<dht::DhtRunner> dht;
47 std::shared_ptr<ConnectionManager> connectionManager;
48 std::shared_ptr<asio::io_context> ioContext;
Amnab8c33bb2023-08-03 14:40:01 -040049 std::shared_ptr<std::thread> ioContextRunner;
Morteza Namvar82960b32023-07-04 17:08:22 -040050};
51
Adrien Béraudefe27372023-05-27 18:56:29 -040052class ConnectionManagerTest : public CppUnit::TestFixture
53{
54public:
Adrien Béraud4796de12023-09-25 14:46:47 -040055 ConnectionManagerTest() {
56 pj_log_set_level(0);
57 pj_log_set_log_func([](int level, const char* data, int /*len*/) {});
58 // logger->debug("Using PJSIP version {} for {}", pj_get_version(), PJ_OS_NAME);
59 // logger->debug("Using GnuTLS version {}", gnutls_check_version(nullptr));
60 // logger->debug("Using OpenDHT version {}", dht::version());
61 }
Amnab8c33bb2023-08-03 14:40:01 -040062 ~ConnectionManagerTest() {}
Adrien Béraudefe27372023-05-27 18:56:29 -040063 static std::string name() { return "ConnectionManager"; }
64 void setUp();
65 void tearDown();
66
Adrien Béraud4796de12023-09-25 14:46:47 -040067 std::shared_ptr<dht::DhtRunner> bootstrap_node;
68 dht::crypto::Identity org1Id, org2Id;
69 dht::crypto::Identity aliceId, bobId;
70 dht::crypto::Identity aliceDevice1Id, bobDevice1Id;
71
Morteza Namvar82960b32023-07-04 17:08:22 -040072 std::unique_ptr<ConnectionHandler> alice;
73 std::unique_ptr<ConnectionHandler> bob;
Adrien Béraudefe27372023-05-27 18:56:29 -040074
Morteza Namvar82960b32023-07-04 17:08:22 -040075 std::mutex mtx;
76 std::shared_ptr<asio::io_context> ioContext;
Amnab8c33bb2023-08-03 14:40:01 -040077 std::shared_ptr<std::thread> ioContextRunner;
Adrien Béraud4796de12023-09-25 14:46:47 -040078 std::shared_ptr<Logger> logger = dht::log::getStdLogger();
Amna81221ad2023-09-14 17:33:26 -040079 std::shared_ptr<IceTransportFactory> factory;
Morteza Namvar82960b32023-07-04 17:08:22 -040080
Amnab8c33bb2023-08-03 14:40:01 -040081private:
Adrien Béraud4796de12023-09-25 14:46:47 -040082 std::unique_ptr<ConnectionHandler> setupHandler(const dht::crypto::Identity& id, const std::string& bootstrap = "bootstrap.jami.net");
Morteza Namvar82960b32023-07-04 17:08:22 -040083
Amnab8c33bb2023-08-03 14:40:01 -040084 void testConnectDevice();
85 void testAcceptConnection();
86 void testMultipleChannels();
87 void testMultipleChannelsOneDeclined();
88 void testMultipleChannelsSameName();
89 void testDeclineConnection();
90 void testSendReceiveData();
91 void testAcceptsICERequest();
92 void testDeclineICERequest();
93 void testChannelRcvShutdown();
94 void testChannelSenderShutdown();
95 void testCloseConnectionWith();
96 void testShutdownCallbacks();
97 void testFloodSocket();
98 void testDestroyWhileSending();
99 void testIsConnecting();
100 void testCanSendBeacon();
101 void testCannotSendBeacon();
102 void testConnectivityChangeTriggerBeacon();
103 void testOnNoBeaconTriggersShutdown();
104 void testShutdownWhileNegotiating();
105 void testGetChannelList();
Adrien Béraudefe27372023-05-27 18:56:29 -0400106 CPPUNIT_TEST_SUITE(ConnectionManagerTest);
Amnab8c33bb2023-08-03 14:40:01 -0400107 CPPUNIT_TEST(testDeclineICERequest);
108 CPPUNIT_TEST(testConnectDevice);
109 CPPUNIT_TEST(testIsConnecting);
110 CPPUNIT_TEST(testAcceptConnection);
111 CPPUNIT_TEST(testDeclineConnection);
112 CPPUNIT_TEST(testMultipleChannels);
113 CPPUNIT_TEST(testMultipleChannelsOneDeclined);
114 CPPUNIT_TEST(testMultipleChannelsSameName);
115 CPPUNIT_TEST(testSendReceiveData);
116 CPPUNIT_TEST(testAcceptsICERequest);
117 CPPUNIT_TEST(testChannelRcvShutdown);
118 CPPUNIT_TEST(testChannelSenderShutdown);
119 CPPUNIT_TEST(testCloseConnectionWith);
120 CPPUNIT_TEST(testShutdownCallbacks);
121 CPPUNIT_TEST(testFloodSocket);
122 CPPUNIT_TEST(testDestroyWhileSending);
123 CPPUNIT_TEST(testCanSendBeacon);
124 CPPUNIT_TEST(testCannotSendBeacon);
125 CPPUNIT_TEST(testConnectivityChangeTriggerBeacon);
126 CPPUNIT_TEST(testOnNoBeaconTriggersShutdown);
127 CPPUNIT_TEST(testShutdownWhileNegotiating);
128 CPPUNIT_TEST(testGetChannelList);
Adrien Béraudefe27372023-05-27 18:56:29 -0400129 CPPUNIT_TEST_SUITE_END();
130};
131
132CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConnectionManagerTest, ConnectionManagerTest::name());
133
Morteza Namvar82960b32023-07-04 17:08:22 -0400134std::unique_ptr<ConnectionHandler>
Adrien Béraud4796de12023-09-25 14:46:47 -0400135ConnectionManagerTest::setupHandler(const dht::crypto::Identity& id, const std::string& bootstrap)
Amnab8c33bb2023-08-03 14:40:01 -0400136{
Morteza Namvar82960b32023-07-04 17:08:22 -0400137 auto h = std::make_unique<ConnectionHandler>();
Adrien Béraud4796de12023-09-25 14:46:47 -0400138 h->id = id;
139 h->logger = {};//logger;
140 h->certStore = std::make_shared<tls::CertificateStore>(id.second->getName(), nullptr/*h->logger*/);
Amnab8c33bb2023-08-03 14:40:01 -0400141 h->ioContext = ioContext;
Amnab8c33bb2023-08-03 14:40:01 -0400142 h->ioContextRunner = ioContextRunner;
Morteza Namvar82960b32023-07-04 17:08:22 -0400143
144 dht::DhtRunner::Config dhtConfig;
145 dhtConfig.dht_config.id = h->id;
146 dhtConfig.threaded = true;
147
148 dht::DhtRunner::Context dhtContext;
Amnab8c33bb2023-08-03 14:40:01 -0400149 dhtContext.certificateStore = [c = h->certStore](const dht::InfoHash& pk_id) {
Morteza Namvar82960b32023-07-04 17:08:22 -0400150 std::vector<std::shared_ptr<dht::crypto::Certificate>> ret;
151 if (auto cert = c->getCertificate(pk_id.toString()))
152 ret.emplace_back(std::move(cert));
153 return ret;
154 };
Amnab8c33bb2023-08-03 14:40:01 -0400155 // dhtContext.logger = h->logger;
Morteza Namvar82960b32023-07-04 17:08:22 -0400156
157 h->dht = std::make_shared<dht::DhtRunner>();
158 h->dht->run(dhtConfig, std::move(dhtContext));
Adrien Béraud4796de12023-09-25 14:46:47 -0400159 h->dht->bootstrap(bootstrap);
Morteza Namvar82960b32023-07-04 17:08:22 -0400160
161 auto config = std::make_shared<ConnectionManager::Config>();
162 config->dht = h->dht;
163 config->id = h->id;
164 config->ioContext = h->ioContext;
Amna81221ad2023-09-14 17:33:26 -0400165 config->factory = factory;
Adrien Béraud4796de12023-09-25 14:46:47 -0400166 // config->logger = logger;
Amna81221ad2023-09-14 17:33:26 -0400167 config->certStore = h->certStore;
Adrien Béraud4796de12023-09-25 14:46:47 -0400168 config->cachePath = std::filesystem::current_path() / id.second->getName() / "temp";
Morteza Namvar82960b32023-07-04 17:08:22 -0400169
170 h->connectionManager = std::make_shared<ConnectionManager>(config);
Amnab8c33bb2023-08-03 14:40:01 -0400171 h->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraud4796de12023-09-25 14:46:47 -0400172 h->connectionManager->onDhtConnected(h->id.first->getPublicKey());
173
Morteza Namvar82960b32023-07-04 17:08:22 -0400174 return h;
175}
176
Adrien Béraudefe27372023-05-27 18:56:29 -0400177void
178ConnectionManagerTest::setUp()
179{
Adrien Béraud4796de12023-09-25 14:46:47 -0400180 if (not org1Id.first) {
181 org1Id = dht::crypto::generateIdentity("org1");
182 org2Id = dht::crypto::generateIdentity("org2");
183 aliceId = dht::crypto::generateIdentity("alice", org1Id, 2048, true);
184 bobId = dht::crypto::generateIdentity("bob", org2Id, 2048, true);
185 aliceDevice1Id = dht::crypto::generateIdentity("aliceDevice1", aliceId);
186 bobDevice1Id = dht::crypto::generateIdentity("bobDevice1", bobId);
187 }
Adrien Béraudc631a832023-07-26 22:19:00 -0400188
Morteza Namvar82960b32023-07-04 17:08:22 -0400189 ioContext = std::make_shared<asio::io_context>();
Amnab8c33bb2023-08-03 14:40:01 -0400190 ioContextRunner = std::make_shared<std::thread>([context = ioContext]() {
Morteza Namvar82960b32023-07-04 17:08:22 -0400191 try {
192 auto work = asio::make_work_guard(*context);
193 context->run();
194 } catch (const std::exception& ex) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400195 fmt::print("Exception in ioContextRunner: {}\n", ex.what());
Morteza Namvar82960b32023-07-04 17:08:22 -0400196 }
197 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400198 bootstrap_node = std::make_shared<dht::DhtRunner>();
199 bootstrap_node->run(36432);
200
201 factory = std::make_unique<IceTransportFactory>(/*logger*/);
202 alice = setupHandler(aliceDevice1Id, "127.0.0.1:36432");
203 bob = setupHandler(bobDevice1Id, "127.0.0.1:36432");
Adrien Béraudefe27372023-05-27 18:56:29 -0400204}
205
206void
207ConnectionManagerTest::tearDown()
208{
Amnab8c33bb2023-08-03 14:40:01 -0400209 // wait_for_removal_of({aliceId, bobId});
210 // Stop the io_context and join the ioContextRunner thread
Morteza Namvar82960b32023-07-04 17:08:22 -0400211 ioContext->stop();
Amnab8c33bb2023-08-03 14:40:01 -0400212
213 if (ioContextRunner && ioContextRunner->joinable()) {
214 ioContextRunner->join();
215 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400216
217 bootstrap_node.reset();
218 alice.reset();
219 bob.reset();
220 factory.reset();
Adrien Béraudefe27372023-05-27 18:56:29 -0400221}
Adrien Béraudefe27372023-05-27 18:56:29 -0400222void
Morteza Namvar82960b32023-07-04 17:08:22 -0400223ConnectionManagerTest::testConnectDevice()
Adrien Béraudefe27372023-05-27 18:56:29 -0400224{
Morteza Namvar82960b32023-07-04 17:08:22 -0400225 std::condition_variable bobConVar;
226 bool isBobRecvChanlReq = false;
Amnab8c33bb2023-08-03 14:40:01 -0400227 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400228 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400229 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400230 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400231 isBobRecvChanlReq = name == "dumyName";
232 bobConVar.notify_one();
233 return true;
234 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400235
Morteza Namvar82960b32023-07-04 17:08:22 -0400236 std::condition_variable alicConVar;
237 bool isAlicConnected = false;
Adrien Béraud4796de12023-09-25 14:46:47 -0400238 alice->connectionManager->connectDevice(bob->id.second, "dumyName", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) {
239 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400240 if (socket) {
241 isAlicConnected = true;
242 }
Morteza Namvar82960b32023-07-04 17:08:22 -0400243 alicConVar.notify_one();
Adrien Béraud4796de12023-09-25 14:46:47 -0400244 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400245
Adrien Béraud4796de12023-09-25 14:46:47 -0400246 std::unique_lock<std::mutex> lock {mtx};
247 CPPUNIT_ASSERT(bobConVar.wait_for(lock, 30s, [&] { return isBobRecvChanlReq; }));
248 CPPUNIT_ASSERT(alicConVar.wait_for(lock, 30s, [&] { return isAlicConnected; }));
Adrien Béraudefe27372023-05-27 18:56:29 -0400249}
250
Amnab8c33bb2023-08-03 14:40:01 -0400251void
252ConnectionManagerTest::testAcceptConnection()
253{
Amnab8c33bb2023-08-03 14:40:01 -0400254 std::unique_lock<std::mutex> lk {mtx};
255 std::condition_variable cv;
256 bool successfullyConnected = false;
257 bool successfullyReceive = false;
258 bool receiverConnected = false;
Adrien Béraudefe27372023-05-27 18:56:29 -0400259
Amnab8c33bb2023-08-03 14:40:01 -0400260 bob->connectionManager->onChannelRequest(
261 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
262 const std::string& name) {
263 successfullyReceive = name == "git://*";
264 return true;
265 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400266
Amnab8c33bb2023-08-03 14:40:01 -0400267 bob->connectionManager->onConnectionReady(
268 [&receiverConnected](const DeviceId&,
269 const std::string& name,
270 std::shared_ptr<ChannelSocket> socket) {
271 receiverConnected = socket && (name == "git://*");
272 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400273
Amnab8c33bb2023-08-03 14:40:01 -0400274 alice->connectionManager->connectDevice(bob->id.second,
275 "git://*",
276 [&](std::shared_ptr<ChannelSocket> socket,
277 const DeviceId&) {
278 if (socket) {
279 successfullyConnected = true;
280 }
281 cv.notify_one();
282 });
283 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
284 return successfullyReceive && successfullyConnected && receiverConnected;
285 }));
286}
Adrien Béraudefe27372023-05-27 18:56:29 -0400287
Amnab8c33bb2023-08-03 14:40:01 -0400288void
289ConnectionManagerTest::testDeclineConnection()
290{
Amnab8c33bb2023-08-03 14:40:01 -0400291 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
292 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400293
Amnab8c33bb2023-08-03 14:40:01 -0400294 std::unique_lock<std::mutex> lk {mtx};
295 std::condition_variable cv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400296 bool connectCompleted = false;
Amnab8c33bb2023-08-03 14:40:01 -0400297 bool successfullyConnected = false;
298 bool successfullyReceive = false;
299 bool receiverConnected = false;
Adrien Béraudefe27372023-05-27 18:56:29 -0400300
Amnab8c33bb2023-08-03 14:40:01 -0400301 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400302 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400303 const std::string&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400304 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400305 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400306 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400307 return false;
308 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400309
Amnab8c33bb2023-08-03 14:40:01 -0400310 bob->connectionManager->onConnectionReady(
311 [&receiverConnected](const DeviceId&,
312 const std::string&,
313 std::shared_ptr<ChannelSocket> socket) {
314 if (socket)
315 receiverConnected = true;
316 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400317
Amnab8c33bb2023-08-03 14:40:01 -0400318 alice->connectionManager->connectDevice(bob->id.second,
319 "git://*",
320 [&](std::shared_ptr<ChannelSocket> socket,
321 const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400322 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400323 if (socket) {
324 successfullyConnected = true;
325 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400326 connectCompleted = true;
Amnab8c33bb2023-08-03 14:40:01 -0400327 cv.notify_one();
328 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400329 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyReceive; }));
330 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return connectCompleted; }));
Amnab8c33bb2023-08-03 14:40:01 -0400331 CPPUNIT_ASSERT(!successfullyConnected);
332 CPPUNIT_ASSERT(!receiverConnected);
333}
Adrien Béraudefe27372023-05-27 18:56:29 -0400334
Amnab8c33bb2023-08-03 14:40:01 -0400335void
336ConnectionManagerTest::testMultipleChannels()
337{
Amnab8c33bb2023-08-03 14:40:01 -0400338 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
339 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400340
Amnab8c33bb2023-08-03 14:40:01 -0400341 std::condition_variable cv;
342 bool successfullyConnected = false;
343 bool successfullyConnected2 = false;
344 int receiverConnected = 0;
Adrien Béraudefe27372023-05-27 18:56:29 -0400345
Amnab8c33bb2023-08-03 14:40:01 -0400346 bob->connectionManager->onChannelRequest(
347 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400348
Amnab8c33bb2023-08-03 14:40:01 -0400349 bob->connectionManager->onConnectionReady(
Adrien Béraud4796de12023-09-25 14:46:47 -0400350 [&](const DeviceId&, const std::string& name,
Amnab8c33bb2023-08-03 14:40:01 -0400351 std::shared_ptr<ChannelSocket> socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400352 if (not name.empty()) {
353 std::lock_guard<std::mutex> lk {mtx};
354 if (socket)
355 receiverConnected += 1;
356 cv.notify_one();
357 }
Amnab8c33bb2023-08-03 14:40:01 -0400358 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400359
Amnab8c33bb2023-08-03 14:40:01 -0400360 alice->connectionManager->connectDevice(bob->id.second,
361 "git://*",
362 [&](std::shared_ptr<ChannelSocket> socket,
363 const DeviceId&) {
364 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400365 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400366 successfullyConnected = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400367 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400368 }
Amnab8c33bb2023-08-03 14:40:01 -0400369 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400370
Amnab8c33bb2023-08-03 14:40:01 -0400371 alice->connectionManager->connectDevice(bob->id.second,
372 "sip://*",
373 [&](std::shared_ptr<ChannelSocket> socket,
374 const DeviceId&) {
375 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400376 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400377 successfullyConnected2 = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400378 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400379 }
Amnab8c33bb2023-08-03 14:40:01 -0400380 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400381
Adrien Béraud4796de12023-09-25 14:46:47 -0400382 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400383 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
384 return successfullyConnected && successfullyConnected2 && receiverConnected == 2;
385 }));
386 CPPUNIT_ASSERT(alice->connectionManager->activeSockets() == 1);
387}
Adrien Béraudefe27372023-05-27 18:56:29 -0400388
Amnab8c33bb2023-08-03 14:40:01 -0400389void
390ConnectionManagerTest::testMultipleChannelsOneDeclined()
391{
Amnab8c33bb2023-08-03 14:40:01 -0400392 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
393 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400394
Amnab8c33bb2023-08-03 14:40:01 -0400395 std::unique_lock<std::mutex> lk {mtx};
396 std::condition_variable cv;
397 bool successfullyNotConnected = false;
398 bool successfullyConnected2 = false;
399 int receiverConnected = 0;
Adrien Béraudefe27372023-05-27 18:56:29 -0400400
Amnab8c33bb2023-08-03 14:40:01 -0400401 bob->connectionManager->onChannelRequest(
402 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string& name) {
403 if (name == "git://*")
404 return false;
405 return true;
406 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400407
Amnab8c33bb2023-08-03 14:40:01 -0400408 bob->connectionManager->onConnectionReady(
409 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
410 if (socket)
411 receiverConnected += 1;
412 cv.notify_one();
413 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400414
Amnab8c33bb2023-08-03 14:40:01 -0400415 alice->connectionManager->connectDevice(bob->id.second,
416 "git://*",
417 [&](std::shared_ptr<ChannelSocket> socket,
418 const DeviceId&) {
419 if (!socket)
420 successfullyNotConnected = true;
421 cv.notify_one();
422 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400423
Amnab8c33bb2023-08-03 14:40:01 -0400424 alice->connectionManager->connectDevice(bob->id.second,
425 "sip://*",
426 [&](std::shared_ptr<ChannelSocket> socket,
427 const DeviceId&) {
428 if (socket)
429 successfullyConnected2 = true;
430 cv.notify_one();
431 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400432
Amnab8c33bb2023-08-03 14:40:01 -0400433 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
434 return successfullyNotConnected && successfullyConnected2 && receiverConnected == 1;
435 }));
436 CPPUNIT_ASSERT(alice->connectionManager->activeSockets() == 1);
437}
Morteza Namvar82960b32023-07-04 17:08:22 -0400438
Amnab8c33bb2023-08-03 14:40:01 -0400439void
440ConnectionManagerTest::testMultipleChannelsSameName()
441{
Amnab8c33bb2023-08-03 14:40:01 -0400442 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
443 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400444
Amnab8c33bb2023-08-03 14:40:01 -0400445 std::unique_lock<std::mutex> lk {mtx};
446 std::condition_variable cv;
447 bool successfullyConnected = false;
448 bool successfullyConnected2 = false;
449 int receiverConnected = 0;
Morteza Namvar82960b32023-07-04 17:08:22 -0400450
Amnab8c33bb2023-08-03 14:40:01 -0400451 bob->connectionManager->onChannelRequest(
452 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400453
Amnab8c33bb2023-08-03 14:40:01 -0400454 bob->connectionManager->onConnectionReady(
455 [&receiverConnected](const DeviceId&,
456 const std::string&,
457 std::shared_ptr<ChannelSocket> socket) {
458 if (socket)
459 receiverConnected += 1;
460 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400461
Amnab8c33bb2023-08-03 14:40:01 -0400462 alice->connectionManager->connectDevice(bob->id.second,
463 "git://*",
464 [&](std::shared_ptr<ChannelSocket> socket,
465 const DeviceId&) {
466 if (socket) {
467 successfullyConnected = true;
468 }
469 cv.notify_one();
470 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400471
Amnab8c33bb2023-08-03 14:40:01 -0400472 // We can open two sockets with the same name, it will be two different channel
473 alice->connectionManager->connectDevice(bob->id.second,
474 "git://*",
475 [&](std::shared_ptr<ChannelSocket> socket,
476 const DeviceId&) {
477 if (socket) {
478 successfullyConnected2 = true;
479 }
480 cv.notify_one();
481 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400482
Amnab8c33bb2023-08-03 14:40:01 -0400483 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
484 return successfullyConnected && successfullyConnected2 && receiverConnected == 2;
485 }));
486}
Morteza Namvar82960b32023-07-04 17:08:22 -0400487
Amnab8c33bb2023-08-03 14:40:01 -0400488void
489ConnectionManagerTest::testSendReceiveData()
490{
Amnab8c33bb2023-08-03 14:40:01 -0400491 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
492 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400493
Amnab8c33bb2023-08-03 14:40:01 -0400494 std::unique_lock<std::mutex> lk {mtx};
495 std::condition_variable cv;
496 std::atomic_int events(0);
497 bool successfullyConnected = false, successfullyConnected2 = false, successfullyReceive = false,
498 receiverConnected = false;
499 const uint8_t buf_other[] = {0x64, 0x65, 0x66, 0x67};
500 const uint8_t buf_test[] = {0x68, 0x69, 0x70, 0x71};
501 bool dataOk = false, dataOk2 = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400502
Amnab8c33bb2023-08-03 14:40:01 -0400503 bob->connectionManager->onChannelRequest(
504 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
505 const std::string&) {
506 successfullyReceive = true;
507 return true;
508 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400509
Amnab8c33bb2023-08-03 14:40:01 -0400510 bob->connectionManager->onConnectionReady(
511 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
512 if (socket && (name == "test" || name == "other")) {
513 receiverConnected = true;
514 std::error_code ec;
515 auto res = socket->waitForData(std::chrono::milliseconds(5000), ec);
516 if (res == 4) {
517 uint8_t buf[4];
518 socket->read(&buf[0], 4, ec);
519 if (name == "test")
520 dataOk = std::equal(std::begin(buf), std::end(buf), std::begin(buf_test));
521 else
522 dataOk2 = std::equal(std::begin(buf), std::end(buf), std::begin(buf_other));
523 events++;
524 cv.notify_one();
525 }
526 }
527 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400528
Amnab8c33bb2023-08-03 14:40:01 -0400529 alice->connectionManager->connectDevice(bob->id.second,
530 "test",
531 [&](std::shared_ptr<ChannelSocket> socket,
532 const DeviceId&) {
533 if (socket) {
534 successfullyConnected = true;
535 std::error_code ec;
536 socket->write(&buf_test[0], 4, ec);
537 }
538 events++;
539 cv.notify_one();
540 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400541
Amnab8c33bb2023-08-03 14:40:01 -0400542 alice->connectionManager->connectDevice(bob->id.second,
543 "other",
544 [&](std::shared_ptr<ChannelSocket> socket,
545 const DeviceId&) {
546 if (socket) {
547 successfullyConnected2 = true;
548 std::error_code ec;
549 socket->write(&buf_other[0], 4, ec);
550 }
551 events++;
552 cv.notify_one();
553 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400554
Amnab8c33bb2023-08-03 14:40:01 -0400555 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
556 return events == 4 && successfullyReceive && successfullyConnected && successfullyConnected2
557 && dataOk && dataOk2;
558 }));
559}
Morteza Namvar82960b32023-07-04 17:08:22 -0400560
Amnab8c33bb2023-08-03 14:40:01 -0400561void
562ConnectionManagerTest::testAcceptsICERequest()
563{
Amnab8c33bb2023-08-03 14:40:01 -0400564 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400565
Amnab8c33bb2023-08-03 14:40:01 -0400566 std::unique_lock<std::mutex> lk {mtx};
567 std::condition_variable cv;
568 bool successfullyConnected = false;
569 bool successfullyReceive = false;
570 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400571
Amnab8c33bb2023-08-03 14:40:01 -0400572 bob->connectionManager->onChannelRequest(
573 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
574 bob->connectionManager->onICERequest([&](const DeviceId&) {
575 successfullyReceive = true;
576 return true;
577 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400578
Amnab8c33bb2023-08-03 14:40:01 -0400579 bob->connectionManager->onConnectionReady(
580 [&receiverConnected](const DeviceId&,
581 const std::string& name,
582 std::shared_ptr<ChannelSocket> socket) {
583 receiverConnected = socket && (name == "git://*");
584 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400585
Amnab8c33bb2023-08-03 14:40:01 -0400586 alice->connectionManager->connectDevice(bob->id.second,
587 "git://*",
588 [&](std::shared_ptr<ChannelSocket> socket,
589 const DeviceId&) {
590 if (socket) {
591 successfullyConnected = true;
592 }
593 cv.notify_one();
594 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400595
Amnab8c33bb2023-08-03 14:40:01 -0400596 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
597 return successfullyReceive && successfullyConnected && receiverConnected;
598 }));
599}
Morteza Namvar82960b32023-07-04 17:08:22 -0400600
Amnab8c33bb2023-08-03 14:40:01 -0400601void
602ConnectionManagerTest::testDeclineICERequest()
603{
Amnab8c33bb2023-08-03 14:40:01 -0400604 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400605
Amnab8c33bb2023-08-03 14:40:01 -0400606 std::condition_variable cv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400607 bool connectCompleted = false;
Amnab8c33bb2023-08-03 14:40:01 -0400608 bool successfullyConnected = false;
609 bool successfullyReceive = false;
610 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400611
Amnab8c33bb2023-08-03 14:40:01 -0400612 bob->connectionManager->onChannelRequest(
613 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
614 bob->connectionManager->onICERequest([&](const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400615 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400616 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400617 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400618 return false;
619 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400620
Amnab8c33bb2023-08-03 14:40:01 -0400621 bob->connectionManager->onConnectionReady(
622 [&receiverConnected](const DeviceId&,
623 const std::string& name,
624 std::shared_ptr<ChannelSocket> socket) {
625 receiverConnected = socket && (name == "git://*");
626 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400627
Amnab8c33bb2023-08-03 14:40:01 -0400628 alice->connectionManager->connectDevice(bob->id.second,
629 "git://*",
630 [&](std::shared_ptr<ChannelSocket> socket,
631 const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400632 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400633 if (socket) {
634 successfullyConnected = true;
635 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400636 connectCompleted = true;
Amnab8c33bb2023-08-03 14:40:01 -0400637 cv.notify_one();
638 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400639
Adrien Béraud4796de12023-09-25 14:46:47 -0400640 std::unique_lock<std::mutex> lk {mtx};
641 CPPUNIT_ASSERT(cv.wait_for(lk, 35s, [&] { return successfullyReceive; }));
642 CPPUNIT_ASSERT(cv.wait_for(lk, 35s, [&] { return connectCompleted; }));
Amnab8c33bb2023-08-03 14:40:01 -0400643 CPPUNIT_ASSERT(!receiverConnected);
644 CPPUNIT_ASSERT(!successfullyConnected);
645}
Morteza Namvar82960b32023-07-04 17:08:22 -0400646
Amnab8c33bb2023-08-03 14:40:01 -0400647void
648ConnectionManagerTest::testChannelRcvShutdown()
649{
Amnab8c33bb2023-08-03 14:40:01 -0400650 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
651 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400652
Amnab8c33bb2023-08-03 14:40:01 -0400653 std::unique_lock<std::mutex> lk {mtx};
654 std::condition_variable cv;
655 bool successfullyConnected = false;
656 bool shutdownReceived = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400657
Amnab8c33bb2023-08-03 14:40:01 -0400658 std::shared_ptr<ChannelSocket> bobSock;
Morteza Namvar82960b32023-07-04 17:08:22 -0400659
Amnab8c33bb2023-08-03 14:40:01 -0400660 bob->connectionManager->onChannelRequest(
661 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400662
Amnab8c33bb2023-08-03 14:40:01 -0400663 bob->connectionManager->onConnectionReady(
664 [&](const DeviceId& did, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
665 if (socket && name == "git://*" && did != bob->id.second->getLongId()) {
666 bobSock = socket;
667 cv.notify_one();
668 }
669 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400670
Amnab8c33bb2023-08-03 14:40:01 -0400671 alice->connectionManager->connectDevice(bob->id.second,
672 "git://*",
673 [&](std::shared_ptr<ChannelSocket> socket,
674 const DeviceId&) {
675 if (socket) {
676 socket->onShutdown([&] {
677 shutdownReceived = true;
678 cv.notify_one();
679 });
680 successfullyConnected = true;
681 cv.notify_one();
682 }
683 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400684
Amnab8c33bb2023-08-03 14:40:01 -0400685 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return bobSock && successfullyConnected; }));
Morteza Namvar82960b32023-07-04 17:08:22 -0400686
Amnab8c33bb2023-08-03 14:40:01 -0400687 bobSock->shutdown();
Morteza Namvar82960b32023-07-04 17:08:22 -0400688
Amnab8c33bb2023-08-03 14:40:01 -0400689 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return shutdownReceived; }));
690}
Morteza Namvar82960b32023-07-04 17:08:22 -0400691
Amnab8c33bb2023-08-03 14:40:01 -0400692void
693ConnectionManagerTest::testChannelSenderShutdown()
694{
Amnab8c33bb2023-08-03 14:40:01 -0400695 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
696 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400697
Amnab8c33bb2023-08-03 14:40:01 -0400698 std::condition_variable rcv, scv;
699 bool successfullyConnected = false;
700 bool successfullyReceive = false;
701 bool receiverConnected = false;
702 bool shutdownReceived = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400703
Amnab8c33bb2023-08-03 14:40:01 -0400704 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400705 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400706 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400707 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400708 successfullyReceive = name == "git://*";
Adrien Béraud4796de12023-09-25 14:46:47 -0400709 rcv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400710 return true;
711 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400712
Amnab8c33bb2023-08-03 14:40:01 -0400713 bob->connectionManager->onConnectionReady(
714 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
715 if (socket) {
716 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400717 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400718 shutdownReceived = true;
719 scv.notify_one();
720 });
721 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400722 if (not name.empty()) {
723 std::lock_guard<std::mutex> lk {mtx};
724 receiverConnected = socket && (name == "git://*");
725 rcv.notify_one();
726 }
Amnab8c33bb2023-08-03 14:40:01 -0400727 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400728
Amnab8c33bb2023-08-03 14:40:01 -0400729 alice->connectionManager->connectDevice(bob->id.second,
730 "git://*",
731 [&](std::shared_ptr<ChannelSocket> socket,
732 const DeviceId&) {
733 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400734 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400735 successfullyConnected = true;
736 rcv.notify_one();
737 socket->shutdown();
738 }
739 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400740
Adrien Béraud4796de12023-09-25 14:46:47 -0400741 std::unique_lock<std::mutex> lk {mtx};
742 rcv.wait_for(lk, 30s, [&] { return successfullyConnected && successfullyReceive && receiverConnected; });
743 scv.wait_for(lk, 30s, [&] { return shutdownReceived; });
Amnab8c33bb2023-08-03 14:40:01 -0400744}
Morteza Namvar82960b32023-07-04 17:08:22 -0400745
Amnab8c33bb2023-08-03 14:40:01 -0400746void
747ConnectionManagerTest::testCloseConnectionWith()
748{
Amnab8c33bb2023-08-03 14:40:01 -0400749 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
750 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400751
Amnab8c33bb2023-08-03 14:40:01 -0400752 auto bobUri = bob->id.second->issuer->getId().toString();
Amnab8c33bb2023-08-03 14:40:01 -0400753 std::condition_variable rcv, scv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400754 unsigned events(0);
Amnab8c33bb2023-08-03 14:40:01 -0400755 bool successfullyConnected = false;
756 bool successfullyReceive = false;
757 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400758
Amnab8c33bb2023-08-03 14:40:01 -0400759 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400760 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400761 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400762 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400763 successfullyReceive = name == "git://*";
764 return true;
765 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400766
Amnab8c33bb2023-08-03 14:40:01 -0400767 bob->connectionManager->onConnectionReady([&](const DeviceId&,
768 const std::string& name,
769 std::shared_ptr<dhtnet::ChannelSocket> socket) {
770 if (socket) {
771 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400772 std::lock_guard<std::mutex> lk {mtx};
773 events++;
Amnab8c33bb2023-08-03 14:40:01 -0400774 scv.notify_one();
775 });
776 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400777 if (not name.empty()) {
778 std::lock_guard<std::mutex> lk {mtx};
779 receiverConnected = socket && (name == "git://*");
780 rcv.notify_one();
781 }
Amnab8c33bb2023-08-03 14:40:01 -0400782 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400783
Adrien Béraud4796de12023-09-25 14:46:47 -0400784 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400785 "git://*",
786 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400787 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400788 if (socket) {
789 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400790 std::lock_guard<std::mutex> lk {mtx};
791 events++;
Amnab8c33bb2023-08-03 14:40:01 -0400792 scv.notify_one();
793 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400794 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400795 successfullyConnected = true;
796 rcv.notify_one();
797 }
798 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400799
Adrien Béraud4796de12023-09-25 14:46:47 -0400800 {
801 std::unique_lock<std::mutex> lk {mtx};
802 rcv.wait_for(lk, 30s, [&] {
803 return successfullyReceive && successfullyConnected && receiverConnected;
804 });
805 }
806 std::this_thread::sleep_for(1s);
Amnab8c33bb2023-08-03 14:40:01 -0400807 // This should trigger onShutdown
808 alice->connectionManager->closeConnectionsWith(bobUri);
Adrien Béraud4796de12023-09-25 14:46:47 -0400809 std::unique_lock<std::mutex> lk {mtx};
810 CPPUNIT_ASSERT(scv.wait_for(lk, 10s, [&] { return events == 2; }));
Amnab8c33bb2023-08-03 14:40:01 -0400811}
Morteza Namvar82960b32023-07-04 17:08:22 -0400812
Amnab8c33bb2023-08-03 14:40:01 -0400813// explain algorithm
814void
815ConnectionManagerTest::testShutdownCallbacks()
816{
Amnab8c33bb2023-08-03 14:40:01 -0400817 auto aliceUri = alice->id.second->issuer->getId().toString();
Morteza Namvar82960b32023-07-04 17:08:22 -0400818
Amnab8c33bb2023-08-03 14:40:01 -0400819 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
820 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400821
Amnab8c33bb2023-08-03 14:40:01 -0400822 std::condition_variable rcv, chan2cv;
823 bool successfullyConnected = false;
824 bool successfullyReceive = false;
825 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400826
Amnab8c33bb2023-08-03 14:40:01 -0400827 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400828 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string& name) {
Amnab8c33bb2023-08-03 14:40:01 -0400829 if (name == "1") {
Adrien Béraud4796de12023-09-25 14:46:47 -0400830 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400831 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400832 rcv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400833 } else {
834 chan2cv.notify_one();
835 // Do not return directly. Let the connection be closed
836 std::this_thread::sleep_for(10s);
837 }
838 return true;
839 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400840
Amnab8c33bb2023-08-03 14:40:01 -0400841 bob->connectionManager->onConnectionReady([&](const DeviceId&,
842 const std::string& name,
843 std::shared_ptr<dhtnet::ChannelSocket> socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400844 if (name == "1") {
845 std::unique_lock<std::mutex> lk {mtx};
846 receiverConnected = (bool)socket;
847 rcv.notify_one();
848 }
Amnab8c33bb2023-08-03 14:40:01 -0400849 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400850
Adrien Béraud4796de12023-09-25 14:46:47 -0400851 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400852 "1",
853 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400854 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400855 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400856 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400857 successfullyConnected = true;
858 rcv.notify_one();
859 }
860 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400861
862 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400863 // Connect first channel. This will initiate a mx sock
864 CPPUNIT_ASSERT(rcv.wait_for(lk, 30s, [&] {
Amnab8c33bb2023-08-03 14:40:01 -0400865 return successfullyReceive && successfullyConnected && receiverConnected;
866 }));
Morteza Namvar82960b32023-07-04 17:08:22 -0400867
Amnab8c33bb2023-08-03 14:40:01 -0400868 // Connect another channel, but close the connection
869 bool channel2NotConnected = false;
Adrien Béraud4796de12023-09-25 14:46:47 -0400870 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400871 "2",
872 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400873 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400874 channel2NotConnected = !socket;
875 rcv.notify_one();
876 });
877 chan2cv.wait_for(lk, 30s);
Morteza Namvar82960b32023-07-04 17:08:22 -0400878
Amnab8c33bb2023-08-03 14:40:01 -0400879 // This should trigger onShutdown for second callback
880 bob->connectionManager->closeConnectionsWith(aliceUri);
881 CPPUNIT_ASSERT(rcv.wait_for(lk, 30s, [&] { return channel2NotConnected; }));
882}
Morteza Namvar82960b32023-07-04 17:08:22 -0400883
Amnab8c33bb2023-08-03 14:40:01 -0400884void
885ConnectionManagerTest::testFloodSocket()
886{
Amnab8c33bb2023-08-03 14:40:01 -0400887 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
888 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400889
Amnab8c33bb2023-08-03 14:40:01 -0400890 std::condition_variable cv;
891 bool successfullyConnected = false;
892 bool successfullyReceive = false;
893 bool receiverConnected = false;
894 std::shared_ptr<dhtnet::ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2,
895 sendSock3;
896 bob->connectionManager->onChannelRequest(
897 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
898 const std::string& name) {
899 successfullyReceive = name == "1";
900 return true;
901 });
902 bob->connectionManager->onConnectionReady([&](const DeviceId&,
903 const std::string& name,
904 std::shared_ptr<dhtnet::ChannelSocket> socket) {
905 receiverConnected = socket != nullptr;
906 if (name == "1")
907 rcvSock1 = socket;
908 else if (name == "2")
909 rcvSock2 = socket;
910 else if (name == "3")
911 rcvSock3 = socket;
912 });
913 alice->connectionManager->connectDevice(bob->id.second,
914 "1",
915 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
916 const DeviceId&) {
917 if (socket) {
918 sendSock = socket;
919 successfullyConnected = true;
920 }
921 cv.notify_one();
922 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400923 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400924 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
925 return successfullyReceive && successfullyConnected && receiverConnected;
926 }));
927 CPPUNIT_ASSERT(receiverConnected);
928 successfullyConnected = false;
929 receiverConnected = false;
930 alice->connectionManager->connectDevice(bob->id.second,
931 "2",
932 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
933 const DeviceId&) {
934 if (socket) {
935 sendSock2 = socket;
936 successfullyConnected = true;
937 }
938 cv.notify_one();
939 });
940 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
941 successfullyConnected = false;
942 receiverConnected = false;
943 alice->connectionManager->connectDevice(bob->id.second,
944 "3",
945 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
946 const DeviceId&) {
947 if (socket) {
948 sendSock3 = socket;
949 successfullyConnected = true;
950 }
951 cv.notify_one();
952 });
953 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
Adrien Béraud4796de12023-09-25 14:46:47 -0400954 constexpr size_t C = 8000;
Amnab8c33bb2023-08-03 14:40:01 -0400955 std::string alphabet, shouldRcv, rcv1, rcv2, rcv3;
Adrien Béraud4796de12023-09-25 14:46:47 -0400956 std::mutex mtx1, mtx2, mtx3;
Amnab8c33bb2023-08-03 14:40:01 -0400957 for (int i = 0; i < 100; ++i)
958 alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM";
Adrien Béraud4796de12023-09-25 14:46:47 -0400959 auto totSize = C * alphabet.size();
960 shouldRcv.reserve(totSize);
961 rcv1.reserve(totSize);
962 rcv2.reserve(totSize);
963 rcv3.reserve(totSize);
Amnab8c33bb2023-08-03 14:40:01 -0400964 rcvSock1->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400965 std::lock_guard<std::mutex> lk {mtx1};
966 rcv1 += std::string_view((const char*)buf, len);
967 if (rcv1.size() == totSize)
968 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400969 return len;
970 });
971 rcvSock2->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400972 std::lock_guard<std::mutex> lk {mtx2};
973 rcv2 += std::string_view((const char*)buf, len);
974 if (rcv2.size() == totSize)
975 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400976 return len;
977 });
978 rcvSock3->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400979 std::lock_guard<std::mutex> lk {mtx3};
980 rcv3 += std::string_view((const char*)buf, len);
981 if (rcv3.size() == totSize)
982 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400983 return len;
984 });
985 for (uint64_t i = 0; i < alphabet.size(); ++i) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400986 auto send = std::string(C, alphabet[i]);
Amnab8c33bb2023-08-03 14:40:01 -0400987 shouldRcv += send;
988 std::error_code ec;
989 sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
990 sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
991 sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
992 CPPUNIT_ASSERT(!ec);
993 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400994 {
995 std::unique_lock<std::mutex> lk {mtx1};
996 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return shouldRcv == rcv1; }));
997 }
998 {
999 std::unique_lock<std::mutex> lk {mtx2};
1000 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return shouldRcv == rcv2; }));
1001 }
1002 {
1003 std::unique_lock<std::mutex> lk {mtx3};
1004 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return shouldRcv == rcv3; }));
1005 }
Amnab8c33bb2023-08-03 14:40:01 -04001006}
Morteza Namvar82960b32023-07-04 17:08:22 -04001007
Amnab8c33bb2023-08-03 14:40:01 -04001008void
1009ConnectionManagerTest::testDestroyWhileSending()
1010{
1011 // Same as test before, but destroy the accounts while sending.
1012 // This test if a segfault occurs
Amnab8c33bb2023-08-03 14:40:01 -04001013 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1014 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Amnab8c33bb2023-08-03 14:40:01 -04001015 std::unique_lock<std::mutex> lk {mtx};
1016 std::condition_variable cv;
1017 bool successfullyConnected = false;
1018 bool successfullyReceive = false;
1019 bool receiverConnected = false;
1020 std::shared_ptr<ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2, sendSock3;
1021 bob->connectionManager->onChannelRequest(
1022 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
1023 const std::string& name) {
1024 successfullyReceive = name == "1";
1025 return true;
1026 });
1027 bob->connectionManager->onConnectionReady(
1028 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
1029 receiverConnected = socket != nullptr;
1030 if (name == "1")
1031 rcvSock1 = socket;
1032 else if (name == "2")
1033 rcvSock2 = socket;
1034 else if (name == "3")
1035 rcvSock3 = socket;
1036 });
1037 alice->connectionManager->connectDevice(bob->id.second,
1038 "1",
1039 [&](std::shared_ptr<ChannelSocket> socket,
1040 const DeviceId&) {
1041 if (socket) {
1042 sendSock = socket;
1043 successfullyConnected = true;
1044 }
1045 cv.notify_one();
1046 });
1047 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
1048 return successfullyReceive && successfullyConnected && receiverConnected;
1049 }));
1050 successfullyConnected = false;
1051 receiverConnected = false;
1052 alice->connectionManager->connectDevice(bob->id.second,
1053 "2",
1054 [&](std::shared_ptr<ChannelSocket> socket,
1055 const DeviceId&) {
1056 if (socket) {
1057 sendSock2 = socket;
1058 successfullyConnected = true;
1059 }
1060 cv.notify_one();
1061 });
1062 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
1063 successfullyConnected = false;
1064 receiverConnected = false;
1065 alice->connectionManager->connectDevice(bob->id.second,
1066 "3",
1067 [&](std::shared_ptr<ChannelSocket> socket,
1068 const DeviceId&) {
1069 if (socket) {
1070 sendSock3 = socket;
1071 successfullyConnected = true;
1072 }
1073 cv.notify_one();
1074 });
1075 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
Amnab8c33bb2023-08-03 14:40:01 -04001076 std::string alphabet;
1077 for (int i = 0; i < 100; ++i)
1078 alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM";
1079 rcvSock1->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1080 rcvSock2->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1081 rcvSock3->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1082 for (uint64_t i = 0; i < alphabet.size(); ++i) {
1083 auto send = std::string(8000, alphabet[i]);
1084 std::error_code ec;
1085 sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1086 sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1087 sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1088 CPPUNIT_ASSERT(!ec);
1089 }
Morteza Namvar82960b32023-07-04 17:08:22 -04001090
Amnab8c33bb2023-08-03 14:40:01 -04001091 // No need to wait, immediately destroy, no segfault must occurs
1092}
Morteza Namvar82960b32023-07-04 17:08:22 -04001093
Amnab8c33bb2023-08-03 14:40:01 -04001094void
1095ConnectionManagerTest::testIsConnecting()
1096{
Amnab8c33bb2023-08-03 14:40:01 -04001097 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1098 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001099
Amnab8c33bb2023-08-03 14:40:01 -04001100 std::unique_lock<std::mutex> lk {mtx};
1101 std::condition_variable cv;
1102 bool successfullyConnected = false, successfullyReceive = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001103
Amnab8c33bb2023-08-03 14:40:01 -04001104 bob->connectionManager->onChannelRequest(
1105 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) {
1106 successfullyReceive = true;
1107 cv.notify_one();
1108 std::this_thread::sleep_for(2s);
1109 return true;
1110 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001111
Amnab8c33bb2023-08-03 14:40:01 -04001112 CPPUNIT_ASSERT(!alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
Morteza Namvar82960b32023-07-04 17:08:22 -04001113
Amnab8c33bb2023-08-03 14:40:01 -04001114 alice->connectionManager->connectDevice(bob->id.second,
1115 "sip",
1116 [&](std::shared_ptr<ChannelSocket> socket,
1117 const DeviceId&) {
1118 if (socket) {
1119 successfullyConnected = true;
1120 }
1121 cv.notify_one();
1122 });
1123 // connectDevice is full async, so isConnecting will be true after a few ms.
1124 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return successfullyReceive; }));
1125 CPPUNIT_ASSERT(alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
1126 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return successfullyConnected; }));
1127 std::this_thread::sleep_for(
1128 std::chrono::milliseconds(100)); // Just to wait for the callback to finish
1129 CPPUNIT_ASSERT(!alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
1130}
Morteza Namvar82960b32023-07-04 17:08:22 -04001131
Amnab8c33bb2023-08-03 14:40:01 -04001132void
1133ConnectionManagerTest::testCanSendBeacon()
1134{
Amnab8c33bb2023-08-03 14:40:01 -04001135 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1136 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001137
Amnab8c33bb2023-08-03 14:40:01 -04001138 std::unique_lock<std::mutex> lk {mtx};
1139 std::condition_variable cv;
1140 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001141
Amnab8c33bb2023-08-03 14:40:01 -04001142 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1143 bob->connectionManager->onChannelRequest(
1144 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1145 bob->connectionManager->onConnectionReady(
1146 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1147 if (socket && socket->name() == "sip")
1148 bobSocket = socket->underlyingSocket();
1149 cv.notify_one();
1150 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001151
Amnab8c33bb2023-08-03 14:40:01 -04001152 alice->connectionManager->connectDevice(bob->id.second,
1153 "sip",
1154 [&](std::shared_ptr<ChannelSocket> socket,
1155 const DeviceId&) {
1156 if (socket) {
1157 aliceSocket = socket->underlyingSocket();
1158 successfullyConnected = true;
1159 }
1160 cv.notify_one();
1161 });
1162 // connectDevice is full async, so isConnecting will be true after a few ms.
1163 CPPUNIT_ASSERT(
1164 cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket && successfullyConnected; }));
1165 CPPUNIT_ASSERT(aliceSocket->canSendBeacon());
Morteza Namvar82960b32023-07-04 17:08:22 -04001166
Amnab8c33bb2023-08-03 14:40:01 -04001167 // Because onConnectionReady is true before version is sent, we can wait a bit
1168 // before canSendBeacon is true.
1169 auto start = std::chrono::steady_clock::now();
1170 auto aliceCanSendBeacon = false;
1171 auto bobCanSendBeacon = false;
1172 do {
1173 aliceCanSendBeacon = aliceSocket->canSendBeacon();
1174 bobCanSendBeacon = bobSocket->canSendBeacon();
1175 if (!bobCanSendBeacon || !aliceCanSendBeacon)
1176 std::this_thread::sleep_for(1s);
1177 } while ((not bobCanSendBeacon or not aliceCanSendBeacon)
1178 and std::chrono::steady_clock::now() - start < 5s);
Morteza Namvar82960b32023-07-04 17:08:22 -04001179
Amnab8c33bb2023-08-03 14:40:01 -04001180 CPPUNIT_ASSERT(bobCanSendBeacon && aliceCanSendBeacon);
1181}
Morteza Namvar82960b32023-07-04 17:08:22 -04001182
Amnab8c33bb2023-08-03 14:40:01 -04001183void
1184ConnectionManagerTest::testCannotSendBeacon()
1185{
Amnab8c33bb2023-08-03 14:40:01 -04001186 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1187 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001188
Amnab8c33bb2023-08-03 14:40:01 -04001189 std::unique_lock<std::mutex> lk {mtx};
1190 std::condition_variable cv;
1191 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001192
Amnab8c33bb2023-08-03 14:40:01 -04001193 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1194 bob->connectionManager->onChannelRequest(
1195 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1196 bob->connectionManager->onConnectionReady(
1197 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1198 if (socket && socket->name() == "sip")
1199 bobSocket = socket->underlyingSocket();
1200 cv.notify_one();
1201 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001202
Amnab8c33bb2023-08-03 14:40:01 -04001203 alice->connectionManager->connectDevice(bob->id.second,
1204 "sip",
1205 [&](std::shared_ptr<ChannelSocket> socket,
1206 const DeviceId&) {
1207 if (socket) {
1208 aliceSocket = socket->underlyingSocket();
1209 successfullyConnected = true;
1210 }
1211 cv.notify_one();
1212 });
1213 // connectDevice is full async, so isConnecting will be true after a few ms.
1214 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001215
Amnab8c33bb2023-08-03 14:40:01 -04001216 int version = 1412;
1217 bobSocket->setOnVersionCb([&](auto v) {
1218 version = v;
1219 cv.notify_one();
1220 });
1221 aliceSocket->setVersion(0);
1222 aliceSocket->sendVersion();
1223 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return version == 0; }));
1224 CPPUNIT_ASSERT(!bobSocket->canSendBeacon());
1225}
Morteza Namvar82960b32023-07-04 17:08:22 -04001226
Amnab8c33bb2023-08-03 14:40:01 -04001227void
1228ConnectionManagerTest::testConnectivityChangeTriggerBeacon()
1229{
Amnab8c33bb2023-08-03 14:40:01 -04001230 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1231 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001232
Amnab8c33bb2023-08-03 14:40:01 -04001233 std::unique_lock<std::mutex> lk {mtx};
1234 std::condition_variable cv;
1235 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001236
Amnab8c33bb2023-08-03 14:40:01 -04001237 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1238 bob->connectionManager->onChannelRequest(
1239 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1240 bob->connectionManager->onConnectionReady(
1241 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1242 if (socket && socket->name() == "sip")
1243 bobSocket = socket->underlyingSocket();
1244 cv.notify_one();
1245 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001246
Amnab8c33bb2023-08-03 14:40:01 -04001247 alice->connectionManager->connectDevice(bob->id.second,
1248 "sip",
1249 [&](std::shared_ptr<ChannelSocket> socket,
1250 const DeviceId&) {
1251 if (socket) {
1252 aliceSocket = socket->underlyingSocket();
1253 successfullyConnected = true;
1254 }
1255 cv.notify_one();
1256 });
1257 // connectDevice is full async, so isConnecting will be true after a few ms.
1258 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001259
Amnab8c33bb2023-08-03 14:40:01 -04001260 bool hasRequest = false;
1261 bobSocket->setOnBeaconCb([&](auto p) {
1262 if (p)
1263 hasRequest = true;
1264 cv.notify_one();
1265 });
1266 alice->connectionManager->connectivityChanged();
1267 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return hasRequest; }));
1268}
Morteza Namvar82960b32023-07-04 17:08:22 -04001269
Amnab8c33bb2023-08-03 14:40:01 -04001270void
1271ConnectionManagerTest::testOnNoBeaconTriggersShutdown()
1272{
Amnab8c33bb2023-08-03 14:40:01 -04001273 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1274 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001275
Amnab8c33bb2023-08-03 14:40:01 -04001276 std::unique_lock<std::mutex> lk {mtx};
1277 std::condition_variable cv;
1278 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001279
Amnab8c33bb2023-08-03 14:40:01 -04001280 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1281 bob->connectionManager->onChannelRequest(
1282 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1283 bob->connectionManager->onConnectionReady(
1284 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1285 if (socket && socket->name() == "sip")
1286 bobSocket = socket->underlyingSocket();
1287 cv.notify_one();
1288 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001289
Amnab8c33bb2023-08-03 14:40:01 -04001290 alice->connectionManager->connectDevice(bob->id.second,
1291 "sip",
1292 [&](std::shared_ptr<ChannelSocket> socket,
1293 const DeviceId&) {
1294 if (socket) {
1295 aliceSocket = socket->underlyingSocket();
1296 successfullyConnected = true;
1297 }
1298 cv.notify_one();
1299 });
1300 // connectDevice is full async, so isConnecting will be true after a few ms.
1301 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001302
Amnab8c33bb2023-08-03 14:40:01 -04001303 bool isClosed = false;
1304 aliceSocket->onShutdown([&] {
1305 isClosed = true;
1306 cv.notify_one();
1307 });
1308 bobSocket->answerToBeacon(false);
1309 alice->connectionManager->connectivityChanged();
1310 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return isClosed; }));
1311}
Morteza Namvar82960b32023-07-04 17:08:22 -04001312
Amnab8c33bb2023-08-03 14:40:01 -04001313void
1314ConnectionManagerTest::testShutdownWhileNegotiating()
1315{
Amnab8c33bb2023-08-03 14:40:01 -04001316 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001317
Amnab8c33bb2023-08-03 14:40:01 -04001318 std::unique_lock<std::mutex> lk {mtx};
1319 std::condition_variable cv;
1320 bool successfullyReceive = false;
1321 bool notConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001322
Amnab8c33bb2023-08-03 14:40:01 -04001323 bob->connectionManager->onICERequest([&](const DeviceId&) {
1324 successfullyReceive = true;
1325 cv.notify_one();
1326 return true;
1327 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001328
Amnab8c33bb2023-08-03 14:40:01 -04001329 alice->connectionManager->connectDevice(bob->id.second,
1330 "git://*",
1331 [&](std::shared_ptr<ChannelSocket> socket,
1332 const DeviceId&) {
1333 notConnected = !socket;
1334 cv.notify_one();
1335 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001336
Amnab8c33bb2023-08-03 14:40:01 -04001337 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyReceive; }));
1338 // Manager::instance().setAccountActive(alice->id.second, false, true);
Morteza Namvar82960b32023-07-04 17:08:22 -04001339
Amnab8c33bb2023-08-03 14:40:01 -04001340 // Just move destruction on another thread.
1341 // dht::threadpool::io().run([conMgr =std::move(alice->connectionManager)] {});
1342 alice->connectionManager.reset();
Morteza Namvar82960b32023-07-04 17:08:22 -04001343
Amnab8c33bb2023-08-03 14:40:01 -04001344 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return notConnected; }));
1345}
Adrien Béraud75754b22023-10-17 09:16:06 -04001346
Amnab8c33bb2023-08-03 14:40:01 -04001347void
1348ConnectionManagerTest::testGetChannelList()
1349{
Amnab8c33bb2023-08-03 14:40:01 -04001350 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
Amnab8c33bb2023-08-03 14:40:01 -04001351 std::condition_variable cv;
1352 std::unique_lock<std::mutex> lk {mtx};
1353 bool successfullyConnected = false;
1354 int receiverConnected = 0;
1355 bob->connectionManager->onChannelRequest(
1356 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1357 bob->connectionManager->onConnectionReady(
Adrien Béraud75754b22023-10-17 09:16:06 -04001358 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1359 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -04001360 if (socket)
1361 receiverConnected += 1;
Amnab8c33bb2023-08-03 14:40:01 -04001362 cv.notify_one();
1363 });
1364 std::string channelId;
1365 alice->connectionManager->connectDevice(bob->id.second,
1366 "git://*",
1367 [&](std::shared_ptr<ChannelSocket> socket,
1368 const DeviceId&) {
Adrien Béraud75754b22023-10-17 09:16:06 -04001369 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -04001370 if (socket) {
Adrien Béraud75754b22023-10-17 09:16:06 -04001371 channelId = fmt::format(FMT_COMPILE("{:x}"), socket->channel());
Amnab8c33bb2023-08-03 14:40:01 -04001372 successfullyConnected = true;
1373 }
Amnab8c33bb2023-08-03 14:40:01 -04001374 cv.notify_one();
1375 });
1376 CPPUNIT_ASSERT(
1377 cv.wait_for(lk, 60s, [&] { return successfullyConnected && receiverConnected == 1; }));
1378 std::vector<std::map<std::string, std::string>> expectedList = {
Adrien Béraud75754b22023-10-17 09:16:06 -04001379 {{"id", channelId}, {"name", "git://*"}}};
Amnab8c33bb2023-08-03 14:40:01 -04001380 auto connectionList = alice->connectionManager->getConnectionList();
1381 CPPUNIT_ASSERT(!connectionList.empty());
1382 const auto& connectionInfo = connectionList[0];
1383 auto it = connectionInfo.find("id");
1384 CPPUNIT_ASSERT(it != connectionInfo.end());
Adrien Béraud75754b22023-10-17 09:16:06 -04001385 auto actualList = alice->connectionManager->getChannelList(it->second);
Amnab8c33bb2023-08-03 14:40:01 -04001386 CPPUNIT_ASSERT(expectedList.size() == actualList.size());
Amnab8c33bb2023-08-03 14:40:01 -04001387 for (const auto& expectedMap : expectedList) {
Adrien Béraud75754b22023-10-17 09:16:06 -04001388 CPPUNIT_ASSERT(std::find(actualList.begin(), actualList.end(), expectedMap)
1389 != actualList.end());
Amnab8c33bb2023-08-03 14:40:01 -04001390 }
1391}
Adrien Béraudefe27372023-05-27 18:56:29 -04001392
1393} // namespace test
Sébastien Blin464bdff2023-07-19 08:02:53 -04001394} // namespace dhtnet
Adrien Béraudefe27372023-05-27 18:56:29 -04001395
Adrien Béraud1ae60aa2023-07-07 09:55:09 -04001396JAMI_TEST_RUNNER(dhtnet::test::ConnectionManagerTest::name())