blob: 946aa2d3df55d04c8971e00b69c166ff53b4b3e2 [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>
26
27#include <cppunit/TestAssert.h>
28#include <cppunit/TestFixture.h>
29#include <cppunit/extensions/HelperMacros.h>
30
31#include <condition_variable>
32#include <iostream>
33#include <filesystem>
34
Adrien Béraudefe27372023-05-27 18:56:29 -040035using namespace std::literals::chrono_literals;
36
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040037namespace dhtnet {
Adrien Béraudefe27372023-05-27 18:56:29 -040038namespace test {
39
Amnab8c33bb2023-08-03 14:40:01 -040040struct ConnectionHandler
41{
Morteza Namvar82960b32023-07-04 17:08:22 -040042 dht::crypto::Identity id;
43 std::shared_ptr<Logger> logger;
44 std::shared_ptr<tls::CertificateStore> certStore;
45 std::shared_ptr<dht::DhtRunner> dht;
46 std::shared_ptr<ConnectionManager> connectionManager;
47 std::shared_ptr<asio::io_context> ioContext;
Amnab8c33bb2023-08-03 14:40:01 -040048 std::shared_ptr<std::thread> ioContextRunner;
Morteza Namvar82960b32023-07-04 17:08:22 -040049};
50
Adrien Béraudefe27372023-05-27 18:56:29 -040051class ConnectionManagerTest : public CppUnit::TestFixture
52{
53public:
Adrien Béraud4796de12023-09-25 14:46:47 -040054 ConnectionManagerTest() {
55 pj_log_set_level(0);
56 pj_log_set_log_func([](int level, const char* data, int /*len*/) {});
57 // logger->debug("Using PJSIP version {} for {}", pj_get_version(), PJ_OS_NAME);
58 // logger->debug("Using GnuTLS version {}", gnutls_check_version(nullptr));
59 // logger->debug("Using OpenDHT version {}", dht::version());
60 }
Amnab8c33bb2023-08-03 14:40:01 -040061 ~ConnectionManagerTest() {}
Adrien Béraudefe27372023-05-27 18:56:29 -040062 static std::string name() { return "ConnectionManager"; }
63 void setUp();
64 void tearDown();
65
Adrien Béraud4796de12023-09-25 14:46:47 -040066 std::shared_ptr<dht::DhtRunner> bootstrap_node;
67 dht::crypto::Identity org1Id, org2Id;
68 dht::crypto::Identity aliceId, bobId;
69 dht::crypto::Identity aliceDevice1Id, bobDevice1Id;
70
Morteza Namvar82960b32023-07-04 17:08:22 -040071 std::unique_ptr<ConnectionHandler> alice;
72 std::unique_ptr<ConnectionHandler> bob;
Adrien Béraudefe27372023-05-27 18:56:29 -040073
Morteza Namvar82960b32023-07-04 17:08:22 -040074 std::mutex mtx;
75 std::shared_ptr<asio::io_context> ioContext;
Amnab8c33bb2023-08-03 14:40:01 -040076 std::shared_ptr<std::thread> ioContextRunner;
Adrien Béraud4796de12023-09-25 14:46:47 -040077 std::shared_ptr<Logger> logger = dht::log::getStdLogger();
Amna81221ad2023-09-14 17:33:26 -040078 std::shared_ptr<IceTransportFactory> factory;
Morteza Namvar82960b32023-07-04 17:08:22 -040079
Amnab8c33bb2023-08-03 14:40:01 -040080private:
Adrien Béraud4796de12023-09-25 14:46:47 -040081 std::unique_ptr<ConnectionHandler> setupHandler(const dht::crypto::Identity& id, const std::string& bootstrap = "bootstrap.jami.net");
Morteza Namvar82960b32023-07-04 17:08:22 -040082
Amnab8c33bb2023-08-03 14:40:01 -040083 void testConnectDevice();
84 void testAcceptConnection();
85 void testMultipleChannels();
86 void testMultipleChannelsOneDeclined();
87 void testMultipleChannelsSameName();
88 void testDeclineConnection();
89 void testSendReceiveData();
90 void testAcceptsICERequest();
91 void testDeclineICERequest();
92 void testChannelRcvShutdown();
93 void testChannelSenderShutdown();
94 void testCloseConnectionWith();
95 void testShutdownCallbacks();
96 void testFloodSocket();
97 void testDestroyWhileSending();
98 void testIsConnecting();
99 void testCanSendBeacon();
100 void testCannotSendBeacon();
101 void testConnectivityChangeTriggerBeacon();
102 void testOnNoBeaconTriggersShutdown();
103 void testShutdownWhileNegotiating();
104 void testGetChannelList();
Adrien Béraudefe27372023-05-27 18:56:29 -0400105 CPPUNIT_TEST_SUITE(ConnectionManagerTest);
Amnab8c33bb2023-08-03 14:40:01 -0400106 CPPUNIT_TEST(testDeclineICERequest);
107 CPPUNIT_TEST(testConnectDevice);
108 CPPUNIT_TEST(testIsConnecting);
109 CPPUNIT_TEST(testAcceptConnection);
110 CPPUNIT_TEST(testDeclineConnection);
111 CPPUNIT_TEST(testMultipleChannels);
112 CPPUNIT_TEST(testMultipleChannelsOneDeclined);
113 CPPUNIT_TEST(testMultipleChannelsSameName);
114 CPPUNIT_TEST(testSendReceiveData);
115 CPPUNIT_TEST(testAcceptsICERequest);
116 CPPUNIT_TEST(testChannelRcvShutdown);
117 CPPUNIT_TEST(testChannelSenderShutdown);
118 CPPUNIT_TEST(testCloseConnectionWith);
119 CPPUNIT_TEST(testShutdownCallbacks);
120 CPPUNIT_TEST(testFloodSocket);
121 CPPUNIT_TEST(testDestroyWhileSending);
122 CPPUNIT_TEST(testCanSendBeacon);
123 CPPUNIT_TEST(testCannotSendBeacon);
124 CPPUNIT_TEST(testConnectivityChangeTriggerBeacon);
125 CPPUNIT_TEST(testOnNoBeaconTriggersShutdown);
126 CPPUNIT_TEST(testShutdownWhileNegotiating);
127 CPPUNIT_TEST(testGetChannelList);
Adrien Béraudefe27372023-05-27 18:56:29 -0400128 CPPUNIT_TEST_SUITE_END();
129};
130
131CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConnectionManagerTest, ConnectionManagerTest::name());
132
Morteza Namvar82960b32023-07-04 17:08:22 -0400133std::unique_ptr<ConnectionHandler>
Adrien Béraud4796de12023-09-25 14:46:47 -0400134ConnectionManagerTest::setupHandler(const dht::crypto::Identity& id, const std::string& bootstrap)
Amnab8c33bb2023-08-03 14:40:01 -0400135{
Morteza Namvar82960b32023-07-04 17:08:22 -0400136 auto h = std::make_unique<ConnectionHandler>();
Adrien Béraud4796de12023-09-25 14:46:47 -0400137 h->id = id;
138 h->logger = {};//logger;
139 h->certStore = std::make_shared<tls::CertificateStore>(id.second->getName(), nullptr/*h->logger*/);
Amnab8c33bb2023-08-03 14:40:01 -0400140 h->ioContext = ioContext;
Amnab8c33bb2023-08-03 14:40:01 -0400141 h->ioContextRunner = ioContextRunner;
Morteza Namvar82960b32023-07-04 17:08:22 -0400142
143 dht::DhtRunner::Config dhtConfig;
144 dhtConfig.dht_config.id = h->id;
145 dhtConfig.threaded = true;
146
147 dht::DhtRunner::Context dhtContext;
Amnab8c33bb2023-08-03 14:40:01 -0400148 dhtContext.certificateStore = [c = h->certStore](const dht::InfoHash& pk_id) {
Morteza Namvar82960b32023-07-04 17:08:22 -0400149 std::vector<std::shared_ptr<dht::crypto::Certificate>> ret;
150 if (auto cert = c->getCertificate(pk_id.toString()))
151 ret.emplace_back(std::move(cert));
152 return ret;
153 };
Amnab8c33bb2023-08-03 14:40:01 -0400154 // dhtContext.logger = h->logger;
Morteza Namvar82960b32023-07-04 17:08:22 -0400155
156 h->dht = std::make_shared<dht::DhtRunner>();
157 h->dht->run(dhtConfig, std::move(dhtContext));
Adrien Béraud4796de12023-09-25 14:46:47 -0400158 h->dht->bootstrap(bootstrap);
Morteza Namvar82960b32023-07-04 17:08:22 -0400159
160 auto config = std::make_shared<ConnectionManager::Config>();
161 config->dht = h->dht;
162 config->id = h->id;
163 config->ioContext = h->ioContext;
Amna81221ad2023-09-14 17:33:26 -0400164 config->factory = factory;
Adrien Béraud4796de12023-09-25 14:46:47 -0400165 // config->logger = logger;
Amna81221ad2023-09-14 17:33:26 -0400166 config->certStore = h->certStore;
Adrien Béraud4796de12023-09-25 14:46:47 -0400167 config->cachePath = std::filesystem::current_path() / id.second->getName() / "temp";
Morteza Namvar82960b32023-07-04 17:08:22 -0400168
169 h->connectionManager = std::make_shared<ConnectionManager>(config);
Amnab8c33bb2023-08-03 14:40:01 -0400170 h->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraud4796de12023-09-25 14:46:47 -0400171 h->connectionManager->onDhtConnected(h->id.first->getPublicKey());
172
Morteza Namvar82960b32023-07-04 17:08:22 -0400173 return h;
174}
175
Adrien Béraudefe27372023-05-27 18:56:29 -0400176void
177ConnectionManagerTest::setUp()
178{
Adrien Béraud4796de12023-09-25 14:46:47 -0400179 if (not org1Id.first) {
180 org1Id = dht::crypto::generateIdentity("org1");
181 org2Id = dht::crypto::generateIdentity("org2");
182 aliceId = dht::crypto::generateIdentity("alice", org1Id, 2048, true);
183 bobId = dht::crypto::generateIdentity("bob", org2Id, 2048, true);
184 aliceDevice1Id = dht::crypto::generateIdentity("aliceDevice1", aliceId);
185 bobDevice1Id = dht::crypto::generateIdentity("bobDevice1", bobId);
186 }
Adrien Béraudc631a832023-07-26 22:19:00 -0400187
Morteza Namvar82960b32023-07-04 17:08:22 -0400188 ioContext = std::make_shared<asio::io_context>();
Amnab8c33bb2023-08-03 14:40:01 -0400189 ioContextRunner = std::make_shared<std::thread>([context = ioContext]() {
Morteza Namvar82960b32023-07-04 17:08:22 -0400190 try {
191 auto work = asio::make_work_guard(*context);
192 context->run();
193 } catch (const std::exception& ex) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400194 fmt::print("Exception in ioContextRunner: {}\n", ex.what());
Morteza Namvar82960b32023-07-04 17:08:22 -0400195 }
196 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400197 bootstrap_node = std::make_shared<dht::DhtRunner>();
198 bootstrap_node->run(36432);
199
200 factory = std::make_unique<IceTransportFactory>(/*logger*/);
201 alice = setupHandler(aliceDevice1Id, "127.0.0.1:36432");
202 bob = setupHandler(bobDevice1Id, "127.0.0.1:36432");
Adrien Béraudefe27372023-05-27 18:56:29 -0400203}
204
205void
206ConnectionManagerTest::tearDown()
207{
Amnab8c33bb2023-08-03 14:40:01 -0400208 // wait_for_removal_of({aliceId, bobId});
209 // Stop the io_context and join the ioContextRunner thread
Morteza Namvar82960b32023-07-04 17:08:22 -0400210 ioContext->stop();
Amnab8c33bb2023-08-03 14:40:01 -0400211
212 if (ioContextRunner && ioContextRunner->joinable()) {
213 ioContextRunner->join();
214 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400215
216 bootstrap_node.reset();
217 alice.reset();
218 bob.reset();
219 factory.reset();
Adrien Béraudefe27372023-05-27 18:56:29 -0400220}
Adrien Béraudefe27372023-05-27 18:56:29 -0400221void
Morteza Namvar82960b32023-07-04 17:08:22 -0400222ConnectionManagerTest::testConnectDevice()
Adrien Béraudefe27372023-05-27 18:56:29 -0400223{
Morteza Namvar82960b32023-07-04 17:08:22 -0400224 std::condition_variable bobConVar;
225 bool isBobRecvChanlReq = false;
Amnab8c33bb2023-08-03 14:40:01 -0400226 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400227 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400228 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400229 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400230 isBobRecvChanlReq = name == "dumyName";
231 bobConVar.notify_one();
232 return true;
233 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400234
Morteza Namvar82960b32023-07-04 17:08:22 -0400235 std::condition_variable alicConVar;
236 bool isAlicConnected = false;
Adrien Béraud4796de12023-09-25 14:46:47 -0400237 alice->connectionManager->connectDevice(bob->id.second, "dumyName", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) {
238 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400239 if (socket) {
240 isAlicConnected = true;
241 }
Morteza Namvar82960b32023-07-04 17:08:22 -0400242 alicConVar.notify_one();
Adrien Béraud4796de12023-09-25 14:46:47 -0400243 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400244
Adrien Béraud4796de12023-09-25 14:46:47 -0400245 std::unique_lock<std::mutex> lock {mtx};
246 CPPUNIT_ASSERT(bobConVar.wait_for(lock, 30s, [&] { return isBobRecvChanlReq; }));
247 CPPUNIT_ASSERT(alicConVar.wait_for(lock, 30s, [&] { return isAlicConnected; }));
Adrien Béraudefe27372023-05-27 18:56:29 -0400248}
249
Amnab8c33bb2023-08-03 14:40:01 -0400250void
251ConnectionManagerTest::testAcceptConnection()
252{
Amnab8c33bb2023-08-03 14:40:01 -0400253 std::unique_lock<std::mutex> lk {mtx};
254 std::condition_variable cv;
255 bool successfullyConnected = false;
256 bool successfullyReceive = false;
257 bool receiverConnected = false;
Adrien Béraudefe27372023-05-27 18:56:29 -0400258
Amnab8c33bb2023-08-03 14:40:01 -0400259 bob->connectionManager->onChannelRequest(
260 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
261 const std::string& name) {
262 successfullyReceive = name == "git://*";
263 return true;
264 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400265
Amnab8c33bb2023-08-03 14:40:01 -0400266 bob->connectionManager->onConnectionReady(
267 [&receiverConnected](const DeviceId&,
268 const std::string& name,
269 std::shared_ptr<ChannelSocket> socket) {
270 receiverConnected = socket && (name == "git://*");
271 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400272
Amnab8c33bb2023-08-03 14:40:01 -0400273 alice->connectionManager->connectDevice(bob->id.second,
274 "git://*",
275 [&](std::shared_ptr<ChannelSocket> socket,
276 const DeviceId&) {
277 if (socket) {
278 successfullyConnected = true;
279 }
280 cv.notify_one();
281 });
282 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
283 return successfullyReceive && successfullyConnected && receiverConnected;
284 }));
285}
Adrien Béraudefe27372023-05-27 18:56:29 -0400286
Amnab8c33bb2023-08-03 14:40:01 -0400287void
288ConnectionManagerTest::testDeclineConnection()
289{
Amnab8c33bb2023-08-03 14:40:01 -0400290 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
291 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400292
Amnab8c33bb2023-08-03 14:40:01 -0400293 std::unique_lock<std::mutex> lk {mtx};
294 std::condition_variable cv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400295 bool connectCompleted = false;
Amnab8c33bb2023-08-03 14:40:01 -0400296 bool successfullyConnected = false;
297 bool successfullyReceive = false;
298 bool receiverConnected = false;
Adrien Béraudefe27372023-05-27 18:56:29 -0400299
Amnab8c33bb2023-08-03 14:40:01 -0400300 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400301 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400302 const std::string&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400303 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400304 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400305 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400306 return false;
307 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400308
Amnab8c33bb2023-08-03 14:40:01 -0400309 bob->connectionManager->onConnectionReady(
310 [&receiverConnected](const DeviceId&,
311 const std::string&,
312 std::shared_ptr<ChannelSocket> socket) {
313 if (socket)
314 receiverConnected = true;
315 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400316
Amnab8c33bb2023-08-03 14:40:01 -0400317 alice->connectionManager->connectDevice(bob->id.second,
318 "git://*",
319 [&](std::shared_ptr<ChannelSocket> socket,
320 const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400321 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400322 if (socket) {
323 successfullyConnected = true;
324 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400325 connectCompleted = true;
Amnab8c33bb2023-08-03 14:40:01 -0400326 cv.notify_one();
327 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400328 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyReceive; }));
329 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return connectCompleted; }));
Amnab8c33bb2023-08-03 14:40:01 -0400330 CPPUNIT_ASSERT(!successfullyConnected);
331 CPPUNIT_ASSERT(!receiverConnected);
332}
Adrien Béraudefe27372023-05-27 18:56:29 -0400333
Amnab8c33bb2023-08-03 14:40:01 -0400334void
335ConnectionManagerTest::testMultipleChannels()
336{
Amnab8c33bb2023-08-03 14:40:01 -0400337 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
338 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400339
Amnab8c33bb2023-08-03 14:40:01 -0400340 std::condition_variable cv;
341 bool successfullyConnected = false;
342 bool successfullyConnected2 = false;
343 int receiverConnected = 0;
Adrien Béraudefe27372023-05-27 18:56:29 -0400344
Amnab8c33bb2023-08-03 14:40:01 -0400345 bob->connectionManager->onChannelRequest(
346 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400347
Amnab8c33bb2023-08-03 14:40:01 -0400348 bob->connectionManager->onConnectionReady(
Adrien Béraud4796de12023-09-25 14:46:47 -0400349 [&](const DeviceId&, const std::string& name,
Amnab8c33bb2023-08-03 14:40:01 -0400350 std::shared_ptr<ChannelSocket> socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400351 if (not name.empty()) {
352 std::lock_guard<std::mutex> lk {mtx};
353 if (socket)
354 receiverConnected += 1;
355 cv.notify_one();
356 }
Amnab8c33bb2023-08-03 14:40:01 -0400357 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400358
Amnab8c33bb2023-08-03 14:40:01 -0400359 alice->connectionManager->connectDevice(bob->id.second,
360 "git://*",
361 [&](std::shared_ptr<ChannelSocket> socket,
362 const DeviceId&) {
363 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400364 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400365 successfullyConnected = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400366 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400367 }
Amnab8c33bb2023-08-03 14:40:01 -0400368 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400369
Amnab8c33bb2023-08-03 14:40:01 -0400370 alice->connectionManager->connectDevice(bob->id.second,
371 "sip://*",
372 [&](std::shared_ptr<ChannelSocket> socket,
373 const DeviceId&) {
374 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400375 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400376 successfullyConnected2 = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400377 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400378 }
Amnab8c33bb2023-08-03 14:40:01 -0400379 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400380
Adrien Béraud4796de12023-09-25 14:46:47 -0400381 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400382 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
383 return successfullyConnected && successfullyConnected2 && receiverConnected == 2;
384 }));
385 CPPUNIT_ASSERT(alice->connectionManager->activeSockets() == 1);
386}
Adrien Béraudefe27372023-05-27 18:56:29 -0400387
Amnab8c33bb2023-08-03 14:40:01 -0400388void
389ConnectionManagerTest::testMultipleChannelsOneDeclined()
390{
Amnab8c33bb2023-08-03 14:40:01 -0400391 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
392 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Adrien Béraudefe27372023-05-27 18:56:29 -0400393
Amnab8c33bb2023-08-03 14:40:01 -0400394 std::unique_lock<std::mutex> lk {mtx};
395 std::condition_variable cv;
396 bool successfullyNotConnected = false;
397 bool successfullyConnected2 = false;
398 int receiverConnected = 0;
Adrien Béraudefe27372023-05-27 18:56:29 -0400399
Amnab8c33bb2023-08-03 14:40:01 -0400400 bob->connectionManager->onChannelRequest(
401 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string& name) {
402 if (name == "git://*")
403 return false;
404 return true;
405 });
Adrien Béraudefe27372023-05-27 18:56:29 -0400406
Amnab8c33bb2023-08-03 14:40:01 -0400407 bob->connectionManager->onConnectionReady(
408 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
409 if (socket)
410 receiverConnected += 1;
411 cv.notify_one();
412 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400413
Amnab8c33bb2023-08-03 14:40:01 -0400414 alice->connectionManager->connectDevice(bob->id.second,
415 "git://*",
416 [&](std::shared_ptr<ChannelSocket> socket,
417 const DeviceId&) {
418 if (!socket)
419 successfullyNotConnected = true;
420 cv.notify_one();
421 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400422
Amnab8c33bb2023-08-03 14:40:01 -0400423 alice->connectionManager->connectDevice(bob->id.second,
424 "sip://*",
425 [&](std::shared_ptr<ChannelSocket> socket,
426 const DeviceId&) {
427 if (socket)
428 successfullyConnected2 = true;
429 cv.notify_one();
430 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400431
Amnab8c33bb2023-08-03 14:40:01 -0400432 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
433 return successfullyNotConnected && successfullyConnected2 && receiverConnected == 1;
434 }));
435 CPPUNIT_ASSERT(alice->connectionManager->activeSockets() == 1);
436}
Morteza Namvar82960b32023-07-04 17:08:22 -0400437
Amnab8c33bb2023-08-03 14:40:01 -0400438void
439ConnectionManagerTest::testMultipleChannelsSameName()
440{
Amnab8c33bb2023-08-03 14:40:01 -0400441 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
442 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400443
Amnab8c33bb2023-08-03 14:40:01 -0400444 std::unique_lock<std::mutex> lk {mtx};
445 std::condition_variable cv;
446 bool successfullyConnected = false;
447 bool successfullyConnected2 = false;
448 int receiverConnected = 0;
Morteza Namvar82960b32023-07-04 17:08:22 -0400449
Amnab8c33bb2023-08-03 14:40:01 -0400450 bob->connectionManager->onChannelRequest(
451 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400452
Amnab8c33bb2023-08-03 14:40:01 -0400453 bob->connectionManager->onConnectionReady(
454 [&receiverConnected](const DeviceId&,
455 const std::string&,
456 std::shared_ptr<ChannelSocket> socket) {
457 if (socket)
458 receiverConnected += 1;
459 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400460
Amnab8c33bb2023-08-03 14:40:01 -0400461 alice->connectionManager->connectDevice(bob->id.second,
462 "git://*",
463 [&](std::shared_ptr<ChannelSocket> socket,
464 const DeviceId&) {
465 if (socket) {
466 successfullyConnected = true;
467 }
468 cv.notify_one();
469 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400470
Amnab8c33bb2023-08-03 14:40:01 -0400471 // We can open two sockets with the same name, it will be two different channel
472 alice->connectionManager->connectDevice(bob->id.second,
473 "git://*",
474 [&](std::shared_ptr<ChannelSocket> socket,
475 const DeviceId&) {
476 if (socket) {
477 successfullyConnected2 = true;
478 }
479 cv.notify_one();
480 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400481
Amnab8c33bb2023-08-03 14:40:01 -0400482 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
483 return successfullyConnected && successfullyConnected2 && receiverConnected == 2;
484 }));
485}
Morteza Namvar82960b32023-07-04 17:08:22 -0400486
Amnab8c33bb2023-08-03 14:40:01 -0400487void
488ConnectionManagerTest::testSendReceiveData()
489{
Amnab8c33bb2023-08-03 14:40:01 -0400490 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
491 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400492
Amnab8c33bb2023-08-03 14:40:01 -0400493 std::unique_lock<std::mutex> lk {mtx};
494 std::condition_variable cv;
495 std::atomic_int events(0);
496 bool successfullyConnected = false, successfullyConnected2 = false, successfullyReceive = false,
497 receiverConnected = false;
498 const uint8_t buf_other[] = {0x64, 0x65, 0x66, 0x67};
499 const uint8_t buf_test[] = {0x68, 0x69, 0x70, 0x71};
500 bool dataOk = false, dataOk2 = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400501
Amnab8c33bb2023-08-03 14:40:01 -0400502 bob->connectionManager->onChannelRequest(
503 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
504 const std::string&) {
505 successfullyReceive = true;
506 return true;
507 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400508
Amnab8c33bb2023-08-03 14:40:01 -0400509 bob->connectionManager->onConnectionReady(
510 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
511 if (socket && (name == "test" || name == "other")) {
512 receiverConnected = true;
513 std::error_code ec;
514 auto res = socket->waitForData(std::chrono::milliseconds(5000), ec);
515 if (res == 4) {
516 uint8_t buf[4];
517 socket->read(&buf[0], 4, ec);
518 if (name == "test")
519 dataOk = std::equal(std::begin(buf), std::end(buf), std::begin(buf_test));
520 else
521 dataOk2 = std::equal(std::begin(buf), std::end(buf), std::begin(buf_other));
522 events++;
523 cv.notify_one();
524 }
525 }
526 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400527
Amnab8c33bb2023-08-03 14:40:01 -0400528 alice->connectionManager->connectDevice(bob->id.second,
529 "test",
530 [&](std::shared_ptr<ChannelSocket> socket,
531 const DeviceId&) {
532 if (socket) {
533 successfullyConnected = true;
534 std::error_code ec;
535 socket->write(&buf_test[0], 4, ec);
536 }
537 events++;
538 cv.notify_one();
539 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400540
Amnab8c33bb2023-08-03 14:40:01 -0400541 alice->connectionManager->connectDevice(bob->id.second,
542 "other",
543 [&](std::shared_ptr<ChannelSocket> socket,
544 const DeviceId&) {
545 if (socket) {
546 successfullyConnected2 = true;
547 std::error_code ec;
548 socket->write(&buf_other[0], 4, ec);
549 }
550 events++;
551 cv.notify_one();
552 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400553
Amnab8c33bb2023-08-03 14:40:01 -0400554 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] {
555 return events == 4 && successfullyReceive && successfullyConnected && successfullyConnected2
556 && dataOk && dataOk2;
557 }));
558}
Morteza Namvar82960b32023-07-04 17:08:22 -0400559
Amnab8c33bb2023-08-03 14:40:01 -0400560void
561ConnectionManagerTest::testAcceptsICERequest()
562{
Amnab8c33bb2023-08-03 14:40:01 -0400563 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400564
Amnab8c33bb2023-08-03 14:40:01 -0400565 std::unique_lock<std::mutex> lk {mtx};
566 std::condition_variable cv;
567 bool successfullyConnected = false;
568 bool successfullyReceive = false;
569 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400570
Amnab8c33bb2023-08-03 14:40:01 -0400571 bob->connectionManager->onChannelRequest(
572 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
573 bob->connectionManager->onICERequest([&](const DeviceId&) {
574 successfullyReceive = true;
575 return true;
576 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400577
Amnab8c33bb2023-08-03 14:40:01 -0400578 bob->connectionManager->onConnectionReady(
579 [&receiverConnected](const DeviceId&,
580 const std::string& name,
581 std::shared_ptr<ChannelSocket> socket) {
582 receiverConnected = socket && (name == "git://*");
583 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400584
Amnab8c33bb2023-08-03 14:40:01 -0400585 alice->connectionManager->connectDevice(bob->id.second,
586 "git://*",
587 [&](std::shared_ptr<ChannelSocket> socket,
588 const DeviceId&) {
589 if (socket) {
590 successfullyConnected = true;
591 }
592 cv.notify_one();
593 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400594
Amnab8c33bb2023-08-03 14:40:01 -0400595 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
596 return successfullyReceive && successfullyConnected && receiverConnected;
597 }));
598}
Morteza Namvar82960b32023-07-04 17:08:22 -0400599
Amnab8c33bb2023-08-03 14:40:01 -0400600void
601ConnectionManagerTest::testDeclineICERequest()
602{
Amnab8c33bb2023-08-03 14:40:01 -0400603 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400604
Amnab8c33bb2023-08-03 14:40:01 -0400605 std::condition_variable cv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400606 bool connectCompleted = false;
Amnab8c33bb2023-08-03 14:40:01 -0400607 bool successfullyConnected = false;
608 bool successfullyReceive = false;
609 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400610
Amnab8c33bb2023-08-03 14:40:01 -0400611 bob->connectionManager->onChannelRequest(
612 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
613 bob->connectionManager->onICERequest([&](const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400614 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400615 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400616 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400617 return false;
618 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400619
Amnab8c33bb2023-08-03 14:40:01 -0400620 bob->connectionManager->onConnectionReady(
621 [&receiverConnected](const DeviceId&,
622 const std::string& name,
623 std::shared_ptr<ChannelSocket> socket) {
624 receiverConnected = socket && (name == "git://*");
625 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400626
Amnab8c33bb2023-08-03 14:40:01 -0400627 alice->connectionManager->connectDevice(bob->id.second,
628 "git://*",
629 [&](std::shared_ptr<ChannelSocket> socket,
630 const DeviceId&) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400631 std::lock_guard<std::mutex> lock {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400632 if (socket) {
633 successfullyConnected = true;
634 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400635 connectCompleted = true;
Amnab8c33bb2023-08-03 14:40:01 -0400636 cv.notify_one();
637 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400638
Adrien Béraud4796de12023-09-25 14:46:47 -0400639 std::unique_lock<std::mutex> lk {mtx};
640 CPPUNIT_ASSERT(cv.wait_for(lk, 35s, [&] { return successfullyReceive; }));
641 CPPUNIT_ASSERT(cv.wait_for(lk, 35s, [&] { return connectCompleted; }));
Amnab8c33bb2023-08-03 14:40:01 -0400642 CPPUNIT_ASSERT(!receiverConnected);
643 CPPUNIT_ASSERT(!successfullyConnected);
644}
Morteza Namvar82960b32023-07-04 17:08:22 -0400645
Amnab8c33bb2023-08-03 14:40:01 -0400646void
647ConnectionManagerTest::testChannelRcvShutdown()
648{
Amnab8c33bb2023-08-03 14:40:01 -0400649 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
650 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400651
Amnab8c33bb2023-08-03 14:40:01 -0400652 std::unique_lock<std::mutex> lk {mtx};
653 std::condition_variable cv;
654 bool successfullyConnected = false;
655 bool shutdownReceived = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400656
Amnab8c33bb2023-08-03 14:40:01 -0400657 std::shared_ptr<ChannelSocket> bobSock;
Morteza Namvar82960b32023-07-04 17:08:22 -0400658
Amnab8c33bb2023-08-03 14:40:01 -0400659 bob->connectionManager->onChannelRequest(
660 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400661
Amnab8c33bb2023-08-03 14:40:01 -0400662 bob->connectionManager->onConnectionReady(
663 [&](const DeviceId& did, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
664 if (socket && name == "git://*" && did != bob->id.second->getLongId()) {
665 bobSock = socket;
666 cv.notify_one();
667 }
668 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400669
Amnab8c33bb2023-08-03 14:40:01 -0400670 alice->connectionManager->connectDevice(bob->id.second,
671 "git://*",
672 [&](std::shared_ptr<ChannelSocket> socket,
673 const DeviceId&) {
674 if (socket) {
675 socket->onShutdown([&] {
676 shutdownReceived = true;
677 cv.notify_one();
678 });
679 successfullyConnected = true;
680 cv.notify_one();
681 }
682 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400683
Amnab8c33bb2023-08-03 14:40:01 -0400684 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return bobSock && successfullyConnected; }));
Morteza Namvar82960b32023-07-04 17:08:22 -0400685
Amnab8c33bb2023-08-03 14:40:01 -0400686 bobSock->shutdown();
Morteza Namvar82960b32023-07-04 17:08:22 -0400687
Amnab8c33bb2023-08-03 14:40:01 -0400688 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return shutdownReceived; }));
689}
Morteza Namvar82960b32023-07-04 17:08:22 -0400690
Amnab8c33bb2023-08-03 14:40:01 -0400691void
692ConnectionManagerTest::testChannelSenderShutdown()
693{
Amnab8c33bb2023-08-03 14:40:01 -0400694 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
695 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400696
Amnab8c33bb2023-08-03 14:40:01 -0400697 std::condition_variable rcv, scv;
698 bool successfullyConnected = false;
699 bool successfullyReceive = false;
700 bool receiverConnected = false;
701 bool shutdownReceived = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400702
Amnab8c33bb2023-08-03 14:40:01 -0400703 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400704 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400705 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400706 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400707 successfullyReceive = name == "git://*";
Adrien Béraud4796de12023-09-25 14:46:47 -0400708 rcv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400709 return true;
710 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400711
Amnab8c33bb2023-08-03 14:40:01 -0400712 bob->connectionManager->onConnectionReady(
713 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
714 if (socket) {
715 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400716 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400717 shutdownReceived = true;
718 scv.notify_one();
719 });
720 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400721 if (not name.empty()) {
722 std::lock_guard<std::mutex> lk {mtx};
723 receiverConnected = socket && (name == "git://*");
724 rcv.notify_one();
725 }
Amnab8c33bb2023-08-03 14:40:01 -0400726 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400727
Amnab8c33bb2023-08-03 14:40:01 -0400728 alice->connectionManager->connectDevice(bob->id.second,
729 "git://*",
730 [&](std::shared_ptr<ChannelSocket> socket,
731 const DeviceId&) {
732 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400733 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400734 successfullyConnected = true;
735 rcv.notify_one();
736 socket->shutdown();
737 }
738 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400739
Adrien Béraud4796de12023-09-25 14:46:47 -0400740 std::unique_lock<std::mutex> lk {mtx};
741 rcv.wait_for(lk, 30s, [&] { return successfullyConnected && successfullyReceive && receiverConnected; });
742 scv.wait_for(lk, 30s, [&] { return shutdownReceived; });
Amnab8c33bb2023-08-03 14:40:01 -0400743}
Morteza Namvar82960b32023-07-04 17:08:22 -0400744
Amnab8c33bb2023-08-03 14:40:01 -0400745void
746ConnectionManagerTest::testCloseConnectionWith()
747{
Amnab8c33bb2023-08-03 14:40:01 -0400748 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
749 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400750
Amnab8c33bb2023-08-03 14:40:01 -0400751 auto bobUri = bob->id.second->issuer->getId().toString();
Amnab8c33bb2023-08-03 14:40:01 -0400752 std::condition_variable rcv, scv;
Adrien Béraud4796de12023-09-25 14:46:47 -0400753 unsigned events(0);
Amnab8c33bb2023-08-03 14:40:01 -0400754 bool successfullyConnected = false;
755 bool successfullyReceive = false;
756 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400757
Amnab8c33bb2023-08-03 14:40:01 -0400758 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400759 [&](const std::shared_ptr<dht::crypto::Certificate>&,
Amnab8c33bb2023-08-03 14:40:01 -0400760 const std::string& name) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400761 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400762 successfullyReceive = name == "git://*";
763 return true;
764 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400765
Amnab8c33bb2023-08-03 14:40:01 -0400766 bob->connectionManager->onConnectionReady([&](const DeviceId&,
767 const std::string& name,
768 std::shared_ptr<dhtnet::ChannelSocket> socket) {
769 if (socket) {
770 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400771 std::lock_guard<std::mutex> lk {mtx};
772 events++;
Amnab8c33bb2023-08-03 14:40:01 -0400773 scv.notify_one();
774 });
775 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400776 if (not name.empty()) {
777 std::lock_guard<std::mutex> lk {mtx};
778 receiverConnected = socket && (name == "git://*");
779 rcv.notify_one();
780 }
Amnab8c33bb2023-08-03 14:40:01 -0400781 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400782
Adrien Béraud4796de12023-09-25 14:46:47 -0400783 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400784 "git://*",
785 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400786 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400787 if (socket) {
788 socket->onShutdown([&] {
Adrien Béraud4796de12023-09-25 14:46:47 -0400789 std::lock_guard<std::mutex> lk {mtx};
790 events++;
Amnab8c33bb2023-08-03 14:40:01 -0400791 scv.notify_one();
792 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400793 std::lock_guard<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400794 successfullyConnected = true;
795 rcv.notify_one();
796 }
797 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400798
Adrien Béraud4796de12023-09-25 14:46:47 -0400799 {
800 std::unique_lock<std::mutex> lk {mtx};
801 rcv.wait_for(lk, 30s, [&] {
802 return successfullyReceive && successfullyConnected && receiverConnected;
803 });
804 }
805 std::this_thread::sleep_for(1s);
Amnab8c33bb2023-08-03 14:40:01 -0400806 // This should trigger onShutdown
807 alice->connectionManager->closeConnectionsWith(bobUri);
Adrien Béraud4796de12023-09-25 14:46:47 -0400808 std::unique_lock<std::mutex> lk {mtx};
809 CPPUNIT_ASSERT(scv.wait_for(lk, 10s, [&] { return events == 2; }));
Amnab8c33bb2023-08-03 14:40:01 -0400810}
Morteza Namvar82960b32023-07-04 17:08:22 -0400811
Amnab8c33bb2023-08-03 14:40:01 -0400812// explain algorithm
813void
814ConnectionManagerTest::testShutdownCallbacks()
815{
Amnab8c33bb2023-08-03 14:40:01 -0400816 auto aliceUri = alice->id.second->issuer->getId().toString();
Morteza Namvar82960b32023-07-04 17:08:22 -0400817
Amnab8c33bb2023-08-03 14:40:01 -0400818 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
819 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400820
Amnab8c33bb2023-08-03 14:40:01 -0400821 std::condition_variable rcv, chan2cv;
822 bool successfullyConnected = false;
823 bool successfullyReceive = false;
824 bool receiverConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -0400825
Amnab8c33bb2023-08-03 14:40:01 -0400826 bob->connectionManager->onChannelRequest(
Adrien Béraud4796de12023-09-25 14:46:47 -0400827 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string& name) {
Amnab8c33bb2023-08-03 14:40:01 -0400828 if (name == "1") {
Adrien Béraud4796de12023-09-25 14:46:47 -0400829 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400830 successfullyReceive = true;
Adrien Béraud4796de12023-09-25 14:46:47 -0400831 rcv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400832 } else {
833 chan2cv.notify_one();
834 // Do not return directly. Let the connection be closed
835 std::this_thread::sleep_for(10s);
836 }
837 return true;
838 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400839
Amnab8c33bb2023-08-03 14:40:01 -0400840 bob->connectionManager->onConnectionReady([&](const DeviceId&,
841 const std::string& name,
842 std::shared_ptr<dhtnet::ChannelSocket> socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400843 if (name == "1") {
844 std::unique_lock<std::mutex> lk {mtx};
845 receiverConnected = (bool)socket;
846 rcv.notify_one();
847 }
Amnab8c33bb2023-08-03 14:40:01 -0400848 });
Morteza Namvar82960b32023-07-04 17:08:22 -0400849
Adrien Béraud4796de12023-09-25 14:46:47 -0400850 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400851 "1",
852 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400853 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400854 if (socket) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400855 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400856 successfullyConnected = true;
857 rcv.notify_one();
858 }
859 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400860
861 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400862 // Connect first channel. This will initiate a mx sock
863 CPPUNIT_ASSERT(rcv.wait_for(lk, 30s, [&] {
Amnab8c33bb2023-08-03 14:40:01 -0400864 return successfullyReceive && successfullyConnected && receiverConnected;
865 }));
Morteza Namvar82960b32023-07-04 17:08:22 -0400866
Amnab8c33bb2023-08-03 14:40:01 -0400867 // Connect another channel, but close the connection
868 bool channel2NotConnected = false;
Adrien Béraud4796de12023-09-25 14:46:47 -0400869 alice->connectionManager->connectDevice(bob->id.second,
Amnab8c33bb2023-08-03 14:40:01 -0400870 "2",
871 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
Adrien Béraud4796de12023-09-25 14:46:47 -0400872 const DeviceId&) {
Amnab8c33bb2023-08-03 14:40:01 -0400873 channel2NotConnected = !socket;
874 rcv.notify_one();
875 });
876 chan2cv.wait_for(lk, 30s);
Morteza Namvar82960b32023-07-04 17:08:22 -0400877
Amnab8c33bb2023-08-03 14:40:01 -0400878 // This should trigger onShutdown for second callback
879 bob->connectionManager->closeConnectionsWith(aliceUri);
880 CPPUNIT_ASSERT(rcv.wait_for(lk, 30s, [&] { return channel2NotConnected; }));
881}
Morteza Namvar82960b32023-07-04 17:08:22 -0400882
Amnab8c33bb2023-08-03 14:40:01 -0400883void
884ConnectionManagerTest::testFloodSocket()
885{
Amnab8c33bb2023-08-03 14:40:01 -0400886 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
887 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -0400888
Amnab8c33bb2023-08-03 14:40:01 -0400889 std::condition_variable cv;
890 bool successfullyConnected = false;
891 bool successfullyReceive = false;
892 bool receiverConnected = false;
893 std::shared_ptr<dhtnet::ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2,
894 sendSock3;
895 bob->connectionManager->onChannelRequest(
896 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
897 const std::string& name) {
898 successfullyReceive = name == "1";
899 return true;
900 });
901 bob->connectionManager->onConnectionReady([&](const DeviceId&,
902 const std::string& name,
903 std::shared_ptr<dhtnet::ChannelSocket> socket) {
904 receiverConnected = socket != nullptr;
905 if (name == "1")
906 rcvSock1 = socket;
907 else if (name == "2")
908 rcvSock2 = socket;
909 else if (name == "3")
910 rcvSock3 = socket;
911 });
912 alice->connectionManager->connectDevice(bob->id.second,
913 "1",
914 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
915 const DeviceId&) {
916 if (socket) {
917 sendSock = socket;
918 successfullyConnected = true;
919 }
920 cv.notify_one();
921 });
Adrien Béraud4796de12023-09-25 14:46:47 -0400922 std::unique_lock<std::mutex> lk {mtx};
Amnab8c33bb2023-08-03 14:40:01 -0400923 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
924 return successfullyReceive && successfullyConnected && receiverConnected;
925 }));
926 CPPUNIT_ASSERT(receiverConnected);
927 successfullyConnected = false;
928 receiverConnected = false;
929 alice->connectionManager->connectDevice(bob->id.second,
930 "2",
931 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
932 const DeviceId&) {
933 if (socket) {
934 sendSock2 = socket;
935 successfullyConnected = true;
936 }
937 cv.notify_one();
938 });
939 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
940 successfullyConnected = false;
941 receiverConnected = false;
942 alice->connectionManager->connectDevice(bob->id.second,
943 "3",
944 [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
945 const DeviceId&) {
946 if (socket) {
947 sendSock3 = socket;
948 successfullyConnected = true;
949 }
950 cv.notify_one();
951 });
952 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
Adrien Béraud4796de12023-09-25 14:46:47 -0400953 constexpr size_t C = 8000;
Amnab8c33bb2023-08-03 14:40:01 -0400954 std::string alphabet, shouldRcv, rcv1, rcv2, rcv3;
Adrien Béraud4796de12023-09-25 14:46:47 -0400955 std::mutex mtx1, mtx2, mtx3;
Amnab8c33bb2023-08-03 14:40:01 -0400956 for (int i = 0; i < 100; ++i)
957 alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM";
Adrien Béraud4796de12023-09-25 14:46:47 -0400958 auto totSize = C * alphabet.size();
959 shouldRcv.reserve(totSize);
960 rcv1.reserve(totSize);
961 rcv2.reserve(totSize);
962 rcv3.reserve(totSize);
Amnab8c33bb2023-08-03 14:40:01 -0400963 rcvSock1->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400964 std::lock_guard<std::mutex> lk {mtx1};
965 rcv1 += std::string_view((const char*)buf, len);
966 if (rcv1.size() == totSize)
967 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400968 return len;
969 });
970 rcvSock2->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400971 std::lock_guard<std::mutex> lk {mtx2};
972 rcv2 += std::string_view((const char*)buf, len);
973 if (rcv2.size() == totSize)
974 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400975 return len;
976 });
977 rcvSock3->setOnRecv([&](const uint8_t* buf, size_t len) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400978 std::lock_guard<std::mutex> lk {mtx3};
979 rcv3 += std::string_view((const char*)buf, len);
980 if (rcv3.size() == totSize)
981 cv.notify_one();
Amnab8c33bb2023-08-03 14:40:01 -0400982 return len;
983 });
984 for (uint64_t i = 0; i < alphabet.size(); ++i) {
Adrien Béraud4796de12023-09-25 14:46:47 -0400985 auto send = std::string(C, alphabet[i]);
Amnab8c33bb2023-08-03 14:40:01 -0400986 shouldRcv += send;
987 std::error_code ec;
988 sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
989 sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
990 sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
991 CPPUNIT_ASSERT(!ec);
992 }
Adrien Béraud4796de12023-09-25 14:46:47 -0400993 {
994 std::unique_lock<std::mutex> lk {mtx1};
995 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return shouldRcv == rcv1; }));
996 }
997 {
998 std::unique_lock<std::mutex> lk {mtx2};
999 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return shouldRcv == rcv2; }));
1000 }
1001 {
1002 std::unique_lock<std::mutex> lk {mtx3};
1003 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return shouldRcv == rcv3; }));
1004 }
Amnab8c33bb2023-08-03 14:40:01 -04001005}
Morteza Namvar82960b32023-07-04 17:08:22 -04001006
Amnab8c33bb2023-08-03 14:40:01 -04001007void
1008ConnectionManagerTest::testDestroyWhileSending()
1009{
1010 // Same as test before, but destroy the accounts while sending.
1011 // This test if a segfault occurs
Amnab8c33bb2023-08-03 14:40:01 -04001012 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1013 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Amnab8c33bb2023-08-03 14:40:01 -04001014 std::unique_lock<std::mutex> lk {mtx};
1015 std::condition_variable cv;
1016 bool successfullyConnected = false;
1017 bool successfullyReceive = false;
1018 bool receiverConnected = false;
1019 std::shared_ptr<ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2, sendSock3;
1020 bob->connectionManager->onChannelRequest(
1021 [&successfullyReceive](const std::shared_ptr<dht::crypto::Certificate>&,
1022 const std::string& name) {
1023 successfullyReceive = name == "1";
1024 return true;
1025 });
1026 bob->connectionManager->onConnectionReady(
1027 [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
1028 receiverConnected = socket != nullptr;
1029 if (name == "1")
1030 rcvSock1 = socket;
1031 else if (name == "2")
1032 rcvSock2 = socket;
1033 else if (name == "3")
1034 rcvSock3 = socket;
1035 });
1036 alice->connectionManager->connectDevice(bob->id.second,
1037 "1",
1038 [&](std::shared_ptr<ChannelSocket> socket,
1039 const DeviceId&) {
1040 if (socket) {
1041 sendSock = socket;
1042 successfullyConnected = true;
1043 }
1044 cv.notify_one();
1045 });
1046 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
1047 return successfullyReceive && successfullyConnected && receiverConnected;
1048 }));
1049 successfullyConnected = false;
1050 receiverConnected = false;
1051 alice->connectionManager->connectDevice(bob->id.second,
1052 "2",
1053 [&](std::shared_ptr<ChannelSocket> socket,
1054 const DeviceId&) {
1055 if (socket) {
1056 sendSock2 = socket;
1057 successfullyConnected = true;
1058 }
1059 cv.notify_one();
1060 });
1061 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
1062 successfullyConnected = false;
1063 receiverConnected = false;
1064 alice->connectionManager->connectDevice(bob->id.second,
1065 "3",
1066 [&](std::shared_ptr<ChannelSocket> socket,
1067 const DeviceId&) {
1068 if (socket) {
1069 sendSock3 = socket;
1070 successfullyConnected = true;
1071 }
1072 cv.notify_one();
1073 });
1074 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected && receiverConnected; }));
Amnab8c33bb2023-08-03 14:40:01 -04001075 std::string alphabet;
1076 for (int i = 0; i < 100; ++i)
1077 alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM";
1078 rcvSock1->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1079 rcvSock2->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1080 rcvSock3->setOnRecv([&](const uint8_t*, size_t len) { return len; });
1081 for (uint64_t i = 0; i < alphabet.size(); ++i) {
1082 auto send = std::string(8000, alphabet[i]);
1083 std::error_code ec;
1084 sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1085 sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1086 sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec);
1087 CPPUNIT_ASSERT(!ec);
1088 }
Morteza Namvar82960b32023-07-04 17:08:22 -04001089
Amnab8c33bb2023-08-03 14:40:01 -04001090 // No need to wait, immediately destroy, no segfault must occurs
1091}
Morteza Namvar82960b32023-07-04 17:08:22 -04001092
Amnab8c33bb2023-08-03 14:40:01 -04001093void
1094ConnectionManagerTest::testIsConnecting()
1095{
Amnab8c33bb2023-08-03 14:40:01 -04001096 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1097 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001098
Amnab8c33bb2023-08-03 14:40:01 -04001099 std::unique_lock<std::mutex> lk {mtx};
1100 std::condition_variable cv;
1101 bool successfullyConnected = false, successfullyReceive = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001102
Amnab8c33bb2023-08-03 14:40:01 -04001103 bob->connectionManager->onChannelRequest(
1104 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) {
1105 successfullyReceive = true;
1106 cv.notify_one();
1107 std::this_thread::sleep_for(2s);
1108 return true;
1109 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001110
Amnab8c33bb2023-08-03 14:40:01 -04001111 CPPUNIT_ASSERT(!alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
Morteza Namvar82960b32023-07-04 17:08:22 -04001112
Amnab8c33bb2023-08-03 14:40:01 -04001113 alice->connectionManager->connectDevice(bob->id.second,
1114 "sip",
1115 [&](std::shared_ptr<ChannelSocket> socket,
1116 const DeviceId&) {
1117 if (socket) {
1118 successfullyConnected = true;
1119 }
1120 cv.notify_one();
1121 });
1122 // connectDevice is full async, so isConnecting will be true after a few ms.
1123 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return successfullyReceive; }));
1124 CPPUNIT_ASSERT(alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
1125 CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return successfullyConnected; }));
1126 std::this_thread::sleep_for(
1127 std::chrono::milliseconds(100)); // Just to wait for the callback to finish
1128 CPPUNIT_ASSERT(!alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
1129}
Morteza Namvar82960b32023-07-04 17:08:22 -04001130
Amnab8c33bb2023-08-03 14:40:01 -04001131void
1132ConnectionManagerTest::testCanSendBeacon()
1133{
Amnab8c33bb2023-08-03 14:40:01 -04001134 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1135 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001136
Amnab8c33bb2023-08-03 14:40:01 -04001137 std::unique_lock<std::mutex> lk {mtx};
1138 std::condition_variable cv;
1139 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001140
Amnab8c33bb2023-08-03 14:40:01 -04001141 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1142 bob->connectionManager->onChannelRequest(
1143 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1144 bob->connectionManager->onConnectionReady(
1145 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1146 if (socket && socket->name() == "sip")
1147 bobSocket = socket->underlyingSocket();
1148 cv.notify_one();
1149 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001150
Amnab8c33bb2023-08-03 14:40:01 -04001151 alice->connectionManager->connectDevice(bob->id.second,
1152 "sip",
1153 [&](std::shared_ptr<ChannelSocket> socket,
1154 const DeviceId&) {
1155 if (socket) {
1156 aliceSocket = socket->underlyingSocket();
1157 successfullyConnected = true;
1158 }
1159 cv.notify_one();
1160 });
1161 // connectDevice is full async, so isConnecting will be true after a few ms.
1162 CPPUNIT_ASSERT(
1163 cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket && successfullyConnected; }));
1164 CPPUNIT_ASSERT(aliceSocket->canSendBeacon());
Morteza Namvar82960b32023-07-04 17:08:22 -04001165
Amnab8c33bb2023-08-03 14:40:01 -04001166 // Because onConnectionReady is true before version is sent, we can wait a bit
1167 // before canSendBeacon is true.
1168 auto start = std::chrono::steady_clock::now();
1169 auto aliceCanSendBeacon = false;
1170 auto bobCanSendBeacon = false;
1171 do {
1172 aliceCanSendBeacon = aliceSocket->canSendBeacon();
1173 bobCanSendBeacon = bobSocket->canSendBeacon();
1174 if (!bobCanSendBeacon || !aliceCanSendBeacon)
1175 std::this_thread::sleep_for(1s);
1176 } while ((not bobCanSendBeacon or not aliceCanSendBeacon)
1177 and std::chrono::steady_clock::now() - start < 5s);
Morteza Namvar82960b32023-07-04 17:08:22 -04001178
Amnab8c33bb2023-08-03 14:40:01 -04001179 CPPUNIT_ASSERT(bobCanSendBeacon && aliceCanSendBeacon);
1180}
Morteza Namvar82960b32023-07-04 17:08:22 -04001181
Amnab8c33bb2023-08-03 14:40:01 -04001182void
1183ConnectionManagerTest::testCannotSendBeacon()
1184{
Amnab8c33bb2023-08-03 14:40:01 -04001185 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1186 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001187
Amnab8c33bb2023-08-03 14:40:01 -04001188 std::unique_lock<std::mutex> lk {mtx};
1189 std::condition_variable cv;
1190 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001191
Amnab8c33bb2023-08-03 14:40:01 -04001192 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1193 bob->connectionManager->onChannelRequest(
1194 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1195 bob->connectionManager->onConnectionReady(
1196 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1197 if (socket && socket->name() == "sip")
1198 bobSocket = socket->underlyingSocket();
1199 cv.notify_one();
1200 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001201
Amnab8c33bb2023-08-03 14:40:01 -04001202 alice->connectionManager->connectDevice(bob->id.second,
1203 "sip",
1204 [&](std::shared_ptr<ChannelSocket> socket,
1205 const DeviceId&) {
1206 if (socket) {
1207 aliceSocket = socket->underlyingSocket();
1208 successfullyConnected = true;
1209 }
1210 cv.notify_one();
1211 });
1212 // connectDevice is full async, so isConnecting will be true after a few ms.
1213 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001214
Amnab8c33bb2023-08-03 14:40:01 -04001215 int version = 1412;
1216 bobSocket->setOnVersionCb([&](auto v) {
1217 version = v;
1218 cv.notify_one();
1219 });
1220 aliceSocket->setVersion(0);
1221 aliceSocket->sendVersion();
1222 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return version == 0; }));
1223 CPPUNIT_ASSERT(!bobSocket->canSendBeacon());
1224}
Morteza Namvar82960b32023-07-04 17:08:22 -04001225
Amnab8c33bb2023-08-03 14:40:01 -04001226void
1227ConnectionManagerTest::testConnectivityChangeTriggerBeacon()
1228{
Amnab8c33bb2023-08-03 14:40:01 -04001229 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1230 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001231
Amnab8c33bb2023-08-03 14:40:01 -04001232 std::unique_lock<std::mutex> lk {mtx};
1233 std::condition_variable cv;
1234 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001235
Amnab8c33bb2023-08-03 14:40:01 -04001236 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1237 bob->connectionManager->onChannelRequest(
1238 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1239 bob->connectionManager->onConnectionReady(
1240 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1241 if (socket && socket->name() == "sip")
1242 bobSocket = socket->underlyingSocket();
1243 cv.notify_one();
1244 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001245
Amnab8c33bb2023-08-03 14:40:01 -04001246 alice->connectionManager->connectDevice(bob->id.second,
1247 "sip",
1248 [&](std::shared_ptr<ChannelSocket> socket,
1249 const DeviceId&) {
1250 if (socket) {
1251 aliceSocket = socket->underlyingSocket();
1252 successfullyConnected = true;
1253 }
1254 cv.notify_one();
1255 });
1256 // connectDevice is full async, so isConnecting will be true after a few ms.
1257 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001258
Amnab8c33bb2023-08-03 14:40:01 -04001259 bool hasRequest = false;
1260 bobSocket->setOnBeaconCb([&](auto p) {
1261 if (p)
1262 hasRequest = true;
1263 cv.notify_one();
1264 });
1265 alice->connectionManager->connectivityChanged();
1266 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return hasRequest; }));
1267}
Morteza Namvar82960b32023-07-04 17:08:22 -04001268
Amnab8c33bb2023-08-03 14:40:01 -04001269void
1270ConnectionManagerTest::testOnNoBeaconTriggersShutdown()
1271{
Amnab8c33bb2023-08-03 14:40:01 -04001272 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
1273 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001274
Amnab8c33bb2023-08-03 14:40:01 -04001275 std::unique_lock<std::mutex> lk {mtx};
1276 std::condition_variable cv;
1277 bool successfullyConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001278
Amnab8c33bb2023-08-03 14:40:01 -04001279 std::shared_ptr<MultiplexedSocket> aliceSocket, bobSocket;
1280 bob->connectionManager->onChannelRequest(
1281 [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1282 bob->connectionManager->onConnectionReady(
1283 [&](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1284 if (socket && socket->name() == "sip")
1285 bobSocket = socket->underlyingSocket();
1286 cv.notify_one();
1287 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001288
Amnab8c33bb2023-08-03 14:40:01 -04001289 alice->connectionManager->connectDevice(bob->id.second,
1290 "sip",
1291 [&](std::shared_ptr<ChannelSocket> socket,
1292 const DeviceId&) {
1293 if (socket) {
1294 aliceSocket = socket->underlyingSocket();
1295 successfullyConnected = true;
1296 }
1297 cv.notify_one();
1298 });
1299 // connectDevice is full async, so isConnecting will be true after a few ms.
1300 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceSocket && bobSocket; }));
Morteza Namvar82960b32023-07-04 17:08:22 -04001301
Amnab8c33bb2023-08-03 14:40:01 -04001302 bool isClosed = false;
1303 aliceSocket->onShutdown([&] {
1304 isClosed = true;
1305 cv.notify_one();
1306 });
1307 bobSocket->answerToBeacon(false);
1308 alice->connectionManager->connectivityChanged();
1309 CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return isClosed; }));
1310}
Morteza Namvar82960b32023-07-04 17:08:22 -04001311
Amnab8c33bb2023-08-03 14:40:01 -04001312void
1313ConnectionManagerTest::testShutdownWhileNegotiating()
1314{
Amnab8c33bb2023-08-03 14:40:01 -04001315 alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
Morteza Namvar82960b32023-07-04 17:08:22 -04001316
Amnab8c33bb2023-08-03 14:40:01 -04001317 std::unique_lock<std::mutex> lk {mtx};
1318 std::condition_variable cv;
1319 bool successfullyReceive = false;
1320 bool notConnected = false;
Morteza Namvar82960b32023-07-04 17:08:22 -04001321
Amnab8c33bb2023-08-03 14:40:01 -04001322 bob->connectionManager->onICERequest([&](const DeviceId&) {
1323 successfullyReceive = true;
1324 cv.notify_one();
1325 return true;
1326 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001327
Amnab8c33bb2023-08-03 14:40:01 -04001328 alice->connectionManager->connectDevice(bob->id.second,
1329 "git://*",
1330 [&](std::shared_ptr<ChannelSocket> socket,
1331 const DeviceId&) {
1332 notConnected = !socket;
1333 cv.notify_one();
1334 });
Morteza Namvar82960b32023-07-04 17:08:22 -04001335
Amnab8c33bb2023-08-03 14:40:01 -04001336 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyReceive; }));
1337 // Manager::instance().setAccountActive(alice->id.second, false, true);
Morteza Namvar82960b32023-07-04 17:08:22 -04001338
Amnab8c33bb2023-08-03 14:40:01 -04001339 // Just move destruction on another thread.
1340 // dht::threadpool::io().run([conMgr =std::move(alice->connectionManager)] {});
1341 alice->connectionManager.reset();
Morteza Namvar82960b32023-07-04 17:08:22 -04001342
Amnab8c33bb2023-08-03 14:40:01 -04001343 CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return notConnected; }));
1344}
1345void
1346ConnectionManagerTest::testGetChannelList()
1347{
Amnab8c33bb2023-08-03 14:40:01 -04001348 bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
Amnab8c33bb2023-08-03 14:40:01 -04001349 std::condition_variable cv;
1350 std::unique_lock<std::mutex> lk {mtx};
1351 bool successfullyConnected = false;
1352 int receiverConnected = 0;
1353 bob->connectionManager->onChannelRequest(
1354 [](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) { return true; });
1355 bob->connectionManager->onConnectionReady(
1356 [&receiverConnected,
1357 &cv](const DeviceId&, const std::string&, std::shared_ptr<ChannelSocket> socket) {
1358 if (socket)
1359 receiverConnected += 1;
Morteza Namvar82960b32023-07-04 17:08:22 -04001360
Amnab8c33bb2023-08-03 14:40:01 -04001361 cv.notify_one();
1362 });
1363 std::string channelId;
1364 alice->connectionManager->connectDevice(bob->id.second,
1365 "git://*",
1366 [&](std::shared_ptr<ChannelSocket> socket,
1367 const DeviceId&) {
1368 if (socket) {
1369 channelId = std::to_string(socket->channel());
1370 successfullyConnected = true;
1371 }
Morteza Namvar82960b32023-07-04 17:08:22 -04001372
Amnab8c33bb2023-08-03 14:40:01 -04001373 cv.notify_one();
1374 });
1375 CPPUNIT_ASSERT(
1376 cv.wait_for(lk, 60s, [&] { return successfullyConnected && receiverConnected == 1; }));
1377 std::vector<std::map<std::string, std::string>> expectedList = {
1378 {{"channel", channelId}, {"channelName", "git://*"}}};
1379 auto connectionList = alice->connectionManager->getConnectionList();
1380 CPPUNIT_ASSERT(!connectionList.empty());
1381 const auto& connectionInfo = connectionList[0];
1382 auto it = connectionInfo.find("id");
1383 CPPUNIT_ASSERT(it != connectionInfo.end());
1384 std::string connectionId = it->second;
1385 auto actualList = alice->connectionManager->getChannelList(connectionId);
1386 CPPUNIT_ASSERT(expectedList.size() == actualList.size());
1387 CPPUNIT_ASSERT(std::equal(expectedList.begin(), expectedList.end(), actualList.begin()));
1388 for (const auto& expectedMap : expectedList) {
1389 auto it = std::find_if(actualList.begin(),
1390 actualList.end(),
1391 [&](const std::map<std::string, std::string>& actualMap) {
1392 return expectedMap.size() == actualMap.size()
1393 && std::equal(expectedMap.begin(),
1394 expectedMap.end(),
1395 actualMap.begin());
1396 });
1397 CPPUNIT_ASSERT(it != actualList.end());
1398 }
1399}
Adrien Béraudefe27372023-05-27 18:56:29 -04001400
1401} // namespace test
Sébastien Blin464bdff2023-07-19 08:02:53 -04001402} // namespace dhtnet
Adrien Béraudefe27372023-05-27 18:56:29 -04001403
Adrien Béraud1ae60aa2023-07-07 09:55:09 -04001404JAMI_TEST_RUNNER(dhtnet::test::ConnectionManagerTest::name())