From d0c92c70165cd2855d6b9688b1e3d490c52907ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Thu, 7 Dec 2023 15:27:51 -0500
Subject: [PATCH] connectionmanager: add isConnected

To check if we're connected with a device

Change-Id: I9d0659c3d6d5e305baabd5c4156a820754bae377
---
 include/connectionmanager.h |  7 +++++++
 src/connectionmanager.cpp   | 10 ++++++++++
 tests/connectionManager.cpp | 37 +++++++++++++++++++++++++++++++++++--
 3 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/include/connectionmanager.h b/include/connectionmanager.h
index e11c27a..5a97280 100644
--- a/include/connectionmanager.h
+++ b/include/connectionmanager.h
@@ -139,6 +139,13 @@ public:
      */
     bool isConnecting(const DeviceId& deviceId, const std::string& name) const;
 
+    /**
+     * Check if we are already connected to a device
+     * @param deviceId      Remote device
+     * @return if connected
+     */
+    bool isConnected(const DeviceId& deviceId) const;
+
     /**
      * Close all connections with a current device
      * @param peerUri      Peer URI
diff --git a/src/connectionmanager.cpp b/src/connectionmanager.cpp
index 5474fa0..87704a8 100644
--- a/src/connectionmanager.cpp
+++ b/src/connectionmanager.cpp
@@ -1883,6 +1883,16 @@ ConnectionManager::isConnecting(const DeviceId& deviceId, const std::string& nam
     return false;
 }
 
+bool
+ConnectionManager::isConnected(const DeviceId& deviceId) const
+{
+    if (auto dinfo = pimpl_->infos_.getDeviceInfo(deviceId)) {
+        std::unique_lock<std::mutex> lk {dinfo->mtx_};
+        return dinfo->getConnectedInfo() != nullptr;
+    }
+    return false;
+}
+
 void
 ConnectionManager::closeConnectionsWith(const std::string& peerUri)
 {
diff --git a/tests/connectionManager.cpp b/tests/connectionManager.cpp
index 0bbe5bf..9d0b162 100644
--- a/tests/connectionManager.cpp
+++ b/tests/connectionManager.cpp
@@ -98,16 +98,19 @@ private:
     void testFloodSocket();
     void testDestroyWhileSending();
     void testIsConnecting();
+    void testIsConnected();
     void testCanSendBeacon();
     void testCannotSendBeacon();
     void testConnectivityChangeTriggerBeacon();
     void testOnNoBeaconTriggersShutdown();
     void testShutdownWhileNegotiating();
     void testGetChannelList();
+
     CPPUNIT_TEST_SUITE(ConnectionManagerTest);
     CPPUNIT_TEST(testDeclineICERequest);
     CPPUNIT_TEST(testConnectDevice);
     CPPUNIT_TEST(testIsConnecting);
+    CPPUNIT_TEST(testIsConnected);
     CPPUNIT_TEST(testAcceptConnection);
     CPPUNIT_TEST(testDeclineConnection);
     CPPUNIT_TEST(testManyChannels);
@@ -199,7 +202,7 @@ ConnectionManagerTest::setUp()
     });
     bootstrap_node = std::make_shared<dht::DhtRunner>();
     bootstrap_node->run(36432);
-    
+
     factory = std::make_unique<IceTransportFactory>(/*logger*/);
     alice = setupHandler(aliceDevice1Id, "127.0.0.1:36432");
     bob = setupHandler(bobDevice1Id, "127.0.0.1:36432");
@@ -994,7 +997,7 @@ ConnectionManagerTest::testShutdownCallbacks()
                                                     rcv.notify_one();
                                                 }
                                             });
-    
+
     std::unique_lock<std::mutex> lk {mtx};
     // Connect first channel. This will initiate a mx sock
     CPPUNIT_ASSERT(rcv.wait_for(lk, 30s, [&] {
@@ -1265,6 +1268,36 @@ ConnectionManagerTest::testIsConnecting()
     CPPUNIT_ASSERT(!alice->connectionManager->isConnecting(bob->id.second->getLongId(), "sip"));
 }
 
+void
+ConnectionManagerTest::testIsConnected()
+{
+    bob->connectionManager->onICERequest([](const DeviceId&) { return true; });
+    alice->connectionManager->onICERequest([](const DeviceId&) { return true; });
+
+    std::unique_lock<std::mutex> lk {mtx};
+    std::condition_variable cv;
+    bool successfullyConnected = false, successfullyReceive = false;
+
+    bob->connectionManager->onChannelRequest(
+        [&](const std::shared_ptr<dht::crypto::Certificate>&, const std::string&) {
+            return true;
+        });
+
+    alice->connectionManager->connectDevice(bob->id.second,
+                                            "sip",
+                                            [&](std::shared_ptr<ChannelSocket> socket,
+                                                const DeviceId&) {
+                                                if (socket) {
+                                                    successfullyConnected = true;
+                                                }
+                                                cv.notify_one();
+                                            });
+    CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return successfullyConnected; }));
+    std::this_thread::sleep_for(
+        std::chrono::milliseconds(100)); // Just to wait for the callback to finish
+    CPPUNIT_ASSERT(alice->connectionManager->isConnected(bob->id.second->getLongId()));
+}
+
 void
 ConnectionManagerTest::testCanSendBeacon()
 {
-- 
GitLab