From fe22b4847e1f925a20c83e3d453b8cae752e56bd Mon Sep 17 00:00:00 2001 From: Jean-Francois Penven <67962328+jepenven-silabs@users.noreply.github.com> Date: Tue, 7 Dec 2021 10:41:05 -0500 Subject: [PATCH] [Group] Add multicast listening on linux (#12342) * Add multicast listening on linux --- .github/workflows/tests.yaml | 67 ++++++++---- scripts/build/build/targets.py | 1 + scripts/build/builders/host.py | 8 +- src/app/server/BUILD.gn | 10 ++ src/app/server/Server.cpp | 10 ++ src/app/tests/TestWriteInteraction.cpp | 3 +- src/darwin/Framework/CHIP/templates/tests.js | 1 - .../Framework/CHIPTests/CHIPClustersTests.m | 101 ------------------ src/inet/UDPEndPoint.cpp | 11 +- src/messaging/ExchangeMgr.cpp | 5 + src/platform/Darwin/InetPlatformConfig.h | 4 + src/platform/Linux/InetPlatformConfig.h | 4 + src/transport/SessionManager.cpp | 47 +++++--- src/transport/TransportMgrBase.cpp | 5 + src/transport/TransportMgrBase.h | 2 + src/transport/raw/Base.h | 10 ++ src/transport/raw/Tuple.h | 35 ++++++ src/transport/raw/UDP.cpp | 17 +++ src/transport/raw/UDP.h | 7 ++ 19 files changed, 199 insertions(+), 149 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 363c44915240aa..4e7cc5b84567c0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -20,7 +20,10 @@ on: workflow_dispatch: concurrency: - group: ${{ github.ref }}-${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.event.number) || (github.event_name == 'workflow_dispatch' && github.run_number) || github.sha }} + group: + ${{ github.ref }}-${{ github.workflow }}-${{ (github.event_name == + 'pull_request' && github.event.number) || (github.event_name == + 'workflow_dispatch' && github.run_number) || github.sha }} cancel-in-progress: true jobs: @@ -29,9 +32,9 @@ jobs: timeout-minutes: 60 strategy: - matrix: - build_variant: [no-ble-tsan] - chip_tool: ["", -same-event-loop] + matrix: + build_variant: [no-ble-tsan] + chip_tool: ["", -same-event-loop] env: BUILD_VARIANT: ${{matrix.build_variant}} CHIP_TOOL_VARIANT: ${{matrix.chip_tool}} @@ -50,7 +53,9 @@ jobs: uses: actions/checkout@v2 with: submodules: true - - name: Try to ensure the directories for core dumping exist and we can write them. + - name: + Try to ensure the directories for core dumping exist and we + can write them. run: | mkdir /tmp/cores || true sysctl -w kernel.core_pattern=/tmp/cores/core.%u.%p.%t || true @@ -62,17 +67,19 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ always() }} && ${{ !env.ACT }} with: - name: bootstrap-logs-linux-${{ matrix.type }}-${{ matrix.eventloop }} + name: + bootstrap-logs-linux-${{ matrix.type }}-${{ + matrix.eventloop }} path: | - .environment/gn_out/.ninja_log - .environment/pigweed-venv/*.log + .environment/gn_out/.ninja_log + .environment/pigweed-venv/*.log - name: Build Apps timeout-minutes: 20 run: | ./scripts/run_in_build_env.sh \ "./scripts/build/build_examples.py \ --target linux-x64-chip-tool-${BUILD_VARIANT}${CHIP_TOOL_VARIANT} \ - --target linux-x64-all-clusters-${BUILD_VARIANT} \ + --target linux-x64-all-clusters-${BUILD_VARIANT}-test-group \ --target linux-x64-tv-app-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ @@ -85,14 +92,16 @@ jobs: --chip-tool ./out/linux-x64-chip-tool-${BUILD_VARIANT}${CHIP_TOOL_VARIANT}/chip-tool \ run \ --iterations 1 \ - --all-clusters-app ./out/linux-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \ + --all-clusters-app ./out/linux-x64-all-clusters-${BUILD_VARIANT}-test-group/chip-all-clusters-app \ --tv-app ./out/linux-x64-tv-app-${BUILD_VARIANT}/chip-tv-app \ " - name: Uploading core files uses: actions/upload-artifact@v2 if: ${{ failure() }} && ${{ !env.ACT }} with: - name: crash-core-linux-${{ matrix.type }}-${{ matrix.eventloop }} + name: + crash-core-linux-${{ matrix.type }}-${{ matrix.eventloop + }} path: /tmp/cores/ # Cores are big; don't hold on to them too long. retention-days: 5 @@ -100,7 +109,9 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ failure() }} && ${{ !env.ACT }} with: - name: crash-objdir-linux-${{ matrix.type }}-${{ matrix.eventloop }} + name: + crash-objdir-linux-${{ matrix.type }}-${{ matrix.eventloop + }} path: objdir-clone/ # objdirs are big; don't hold on to them too long. retention-days: 5 @@ -109,9 +120,9 @@ jobs: timeout-minutes: 60 strategy: - matrix: - build_variant: [no-ble-tsan, no-ble-asan] - chip_tool: ["", -same-event-loop] + matrix: + build_variant: [no-ble-tsan, no-ble-asan] + chip_tool: ["", -same-event-loop] env: BUILD_VARIANT: ${{matrix.build_variant}} CHIP_TOOL_VARIANT: ${{matrix.chip_tool}} @@ -127,7 +138,9 @@ jobs: - name: Setup Environment # coreutils for stdbuf run: brew install openssl pkg-config coreutils - - name: Try to ensure the directories for core dumping and diagnostic log collection exist and we can write them. + - name: + Try to ensure the directories for core dumping and diagnostic + log collection exist and we can write them. run: | sudo chown ${USER} /cores || true mkdir -p ~/Library/Logs/DiagnosticReports || true @@ -147,10 +160,12 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ always() }} && ${{ !env.ACT }} with: - name: bootstrap-logs-darwin-${{ matrix.type }}-${{ matrix.eventloop }} + name: + bootstrap-logs-darwin-${{ matrix.type }}-${{ + matrix.eventloop }} path: | - .environment/gn_out/.ninja_log - .environment/pigweed-venv/*.log + .environment/gn_out/.ninja_log + .environment/pigweed-venv/*.log - name: Build Apps timeout-minutes: 20 run: | @@ -167,7 +182,7 @@ jobs: ./scripts/run_in_build_env.sh \ "./scripts/tests/run_test_suite.py \ --chip-tool ./out/darwin-x64-chip-tool-${BUILD_VARIANT}${CHIP_TOOL_VARIANT}/chip-tool \ - --target-skip-glob 'TV*' \ + --target-skip-glob '{TestGroupMessaging,TV_*}' \ run \ --iterations 1 \ --all-clusters-app ./out/darwin-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \ @@ -176,7 +191,9 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ failure() }} && ${{ !env.ACT }} with: - name: crash-core-darwin-${{ matrix.type }}-${{ matrix.eventloop }} + name: + crash-core-darwin-${{ matrix.type }}-${{ matrix.eventloop + }} path: /cores/ # Cores are big; don't hold on to them too long. retention-days: 5 @@ -184,13 +201,17 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ failure() }} && ${{ !env.ACT }} with: - name: crash-log-darwin-${{ matrix.type }}-${{ matrix.eventloop }} + name: + crash-log-darwin-${{ matrix.type }}-${{ matrix.eventloop + }} path: ~/Library/Logs/DiagnosticReports/ - name: Uploading objdir for debugging uses: actions/upload-artifact@v2 if: ${{ failure() }} && ${{ !env.ACT }} with: - name: crash-objdir-darwin-${{ matrix.type }}-${{ matrix.eventloop }} + name: + crash-objdir-darwin-${{ matrix.type }}-${{ + matrix.eventloop }} path: objdir-clone/ # objdirs are big; don't hold on to them too long. retention-days: 5 diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 8e0ee0eb01dfa7..725bc77f330658 100644 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -157,6 +157,7 @@ def HostTargets(): HostBuildVariant(name="no-ble", enable_ble=False), HostBuildVariant(name="tsan", conflicts=['asan'], use_tsan=True), HostBuildVariant(name="asan", conflicts=['tsan'], use_asan=True), + HostBuildVariant(name="test-group", test_group=True), HostBuildVariant(name="same-event-loop", validator=AcceptNameWithSubstring('-chip-tool'), separate_event_loop=False), ] diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index f0cdabf91674b5..cb6d3d84c1eb00 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -106,8 +106,8 @@ def PlatformName(self): class HostBuilder(GnBuilder): def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, enable_ipv4=True, - enable_ble=True, use_tsan=False, use_asan=False, separate_event_loop=True - ): + enable_ble=True, use_tsan=False, use_asan=False, separate_event_loop=True, + test_group=False): super(HostBuilder, self).__init__( root=os.path.join(root, 'examples', app.ExamplePath()), runner=runner) @@ -131,6 +131,10 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, enable_ip if not separate_event_loop: self.extra_gn_options.append('config_use_separate_eventloop=false') + if test_group: + self.extra_gn_options.append( + 'chip_enable_group_messaging_tests=true') + def GnBuildArgs(self): if self.board == HostBoard.NATIVE: return self.extra_gn_options diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 24fcdde4221edb..7a9d332d888b9f 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -15,12 +15,22 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/app/common_flags.gni") +# Move this inside the GroupDataProvider once implemented Issue #11075 +declare_args() { + #Enable Multicast listenening on HardCoded IPV6 address for Test suite + chip_enable_group_messaging_tests = false +} + config("server_config") { defines = [] if (chip_app_use_echo) { defines += [ "CHIP_APP_USE_ECHO" ] } + + if (chip_enable_group_messaging_tests) { + defines += [ "CHIP_ENABLE_GROUP_MESSAGING_TESTS" ] + } } static_library("server") { diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 35175deb1669e6..844cdee7dd1e99 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -117,6 +117,16 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint #endif SuccessOrExit(err); + // Enable Group Listening + // TODO : Fix this once GroupDataProvider is implemented #Issue 11075 + // for (iterate through all GroupDataProvider multicast Address) + // { +#ifdef CHIP_ENABLE_GROUP_MESSAGING_TESTS + err = mTransports.MulticastGroupJoinLeave(Transport::PeerAddress::Multicast(1, 1234), true); + SuccessOrExit(err); +#endif + //} + err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager); SuccessOrExit(err); diff --git a/src/app/tests/TestWriteInteraction.cpp b/src/app/tests/TestWriteInteraction.cpp index 27cd0db58a4b92..115b5773bbcf72 100644 --- a/src/app/tests/TestWriteInteraction.cpp +++ b/src/app/tests/TestWriteInteraction.cpp @@ -261,8 +261,7 @@ void TestWriteInteraction::TestWriteClientGroup(nlTestSuite * apSuite, void * ap err = writeClientHandle.SendWriteRequest(groupSession); - // Write will fail until issue #11078 is completed - NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_NOT_CONNECTED); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); // The internal WriteClient should be shutdown once we SendWriteRequest for group. NL_TEST_ASSERT(apSuite, nullptr == writeClientHandle.mpWriteClient); } diff --git a/src/darwin/Framework/CHIP/templates/tests.js b/src/darwin/Framework/CHIP/templates/tests.js index b5f0f2d0ea8e1d..1a2eaed22404d2 100644 --- a/src/darwin/Framework/CHIP/templates/tests.js +++ b/src/darwin/Framework/CHIP/templates/tests.js @@ -172,7 +172,6 @@ function getTests() 'TestIdentifyCluster', 'TestOperationalCredentialsCluster', 'TestModeSelectCluster', - 'TestGroupMessaging', ]; const SoftwareDiagnostics = [ diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index fe2760c03c9c9c..94a24e62c50760 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -31214,107 +31214,6 @@ - (void)testSendClusterTestModeSelectCluster_000008_ChangeToMode [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } -- (void)testSendClusterTestGroupMessaging_000000_WaitForCommissionee -{ - XCTestExpectation * expectation = [self expectationWithDescription:@"Wait for the commissioned device to be retrieved"]; - - dispatch_queue_t queue = dispatch_get_main_queue(); - WaitForCommissionee(expectation, queue); - [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; -} -- (void)testSendClusterTestGroupMessaging_000001_WriteAttribute -{ - XCTestExpectation * expectation = [self expectationWithDescription:@"Group Write Attribute"]; - - CHIPDevice * device = GetConnectedDevice(); - dispatch_queue_t queue = dispatch_get_main_queue(); - CHIPTestBasic * cluster = [[CHIPTestBasic alloc] initWithDevice:device endpoint:0 queue:queue]; - XCTAssertNotNil(cluster); - - id locationArgument; - locationArgument = @"us"; - [cluster writeAttributeLocationWithValue:locationArgument - completionHandler:^(NSError * _Nullable err) { - NSLog(@"Group Write Attribute Error: %@", err); - - XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); - - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; -} -- (void)testSendClusterTestGroupMessaging_000002_ReadAttribute -{ - XCTestExpectation * expectation = [self expectationWithDescription:@"Read back Attribute"]; - - CHIPDevice * device = GetConnectedDevice(); - dispatch_queue_t queue = dispatch_get_main_queue(); - CHIPTestBasic * cluster = [[CHIPTestBasic alloc] initWithDevice:device endpoint:0 queue:queue]; - XCTAssertNotNil(cluster); - - [cluster readAttributeLocationWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { - NSLog(@"Read back Attribute Error: %@", err); - - XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); - - { - id actualValue = value; - XCTAssertTrue([actualValue isEqualToString:@"us"]); - } - - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; -} -- (void)testSendClusterTestGroupMessaging_000003_WriteAttribute -{ - XCTestExpectation * expectation = [self expectationWithDescription:@"Restore initial location value"]; - - CHIPDevice * device = GetConnectedDevice(); - dispatch_queue_t queue = dispatch_get_main_queue(); - CHIPTestBasic * cluster = [[CHIPTestBasic alloc] initWithDevice:device endpoint:0 queue:queue]; - XCTAssertNotNil(cluster); - - id locationArgument; - locationArgument = @""; - [cluster writeAttributeLocationWithValue:locationArgument - completionHandler:^(NSError * _Nullable err) { - NSLog(@"Restore initial location value Error: %@", err); - - XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); - - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; -} -- (void)testSendClusterTestGroupMessaging_000004_ReadAttribute -{ - XCTestExpectation * expectation = [self expectationWithDescription:@"Read back Attribute"]; - - CHIPDevice * device = GetConnectedDevice(); - dispatch_queue_t queue = dispatch_get_main_queue(); - CHIPTestBasic * cluster = [[CHIPTestBasic alloc] initWithDevice:device endpoint:0 queue:queue]; - XCTAssertNotNil(cluster); - - [cluster readAttributeLocationWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { - NSLog(@"Read back Attribute Error: %@", err); - - XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); - - { - id actualValue = value; - XCTAssertTrue([actualValue isEqualToString:@""]); - } - - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; -} - - (void)testSendClusterTest_TC_DIAGSW_1_1_000000_WaitForCommissionee { XCTestExpectation * expectation = [self expectationWithDescription:@"Wait for the commissioned device to be retrieved"]; diff --git a/src/inet/UDPEndPoint.cpp b/src/inet/UDPEndPoint.cpp index 27d94189f2647e..578e7fc4f77d4d 100644 --- a/src/inet/UDPEndPoint.cpp +++ b/src/inet/UDPEndPoint.cpp @@ -136,7 +136,6 @@ namespace { CHIP_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress & aAddress) { - VerifyOrReturnError(aInterfaceId.IsPresent(), INET_ERROR_UNKNOWN_INTERFACE); VerifyOrReturnError(aAddress.IsMulticast(), INET_ERROR_WRONG_ADDRESS_TYPE); return CHIP_NO_ERROR; } @@ -1419,7 +1418,7 @@ CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId a } #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API -#if defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) +#ifdef IPV6_MULTICAST_IMPLEMENTED const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface(); struct ipv6_mreq lMulticastRequest; @@ -1435,9 +1434,9 @@ CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId a return CHIP_ERROR_POSIX(errno); } return CHIP_NO_ERROR; -#else // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif } #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS @@ -2023,7 +2022,7 @@ void UDPEndPoint::Close() CHIP_ERROR UDPEndPoint::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress) { - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + CHIP_ERROR lRetval = CHIP_NO_ERROR; const IPAddressType lAddrType = aAddress.Type(); lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress); diff --git a/src/messaging/ExchangeMgr.cpp b/src/messaging/ExchangeMgr.cpp index 932142bc4755cb..fec0426bbd0cb9 100644 --- a/src/messaging/ExchangeMgr.cpp +++ b/src/messaging/ExchangeMgr.cpp @@ -237,6 +237,11 @@ void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const return; } } + else + { + ChipLogProgress(ExchangeManager, "Received Groupcast Message with GroupId of %d", + packetHeader.GetDestinationGroupId().Value()); + } // If it's not a duplicate message, search for an unsolicited message handler if it is marked as being sent by an initiator. // Since we didn't find an existing exchange that matches the message, it must be an unsolicited message. However all diff --git a/src/platform/Darwin/InetPlatformConfig.h b/src/platform/Darwin/InetPlatformConfig.h index 07eb63b095db0e..34fba57ba31d8e 100644 --- a/src/platform/Darwin/InetPlatformConfig.h +++ b/src/platform/Darwin/InetPlatformConfig.h @@ -36,6 +36,10 @@ #define INET_CONFIG_NUM_TCP_ENDPOINTS 32 #endif // INET_CONFIG_NUM_TCP_ENDPOINTS +#ifndef IPV6_MULTICAST_IMPLEMENTED +#define IPV6_MULTICAST_IMPLEMENTED +#endif + #ifndef INET_CONFIG_NUM_UDP_ENDPOINTS #define INET_CONFIG_NUM_UDP_ENDPOINTS 32 #endif // INET_CONFIG_NUM_UDP_ENDPOINTS diff --git a/src/platform/Linux/InetPlatformConfig.h b/src/platform/Linux/InetPlatformConfig.h index e951147040e52f..3aab9a7b9b9cd9 100644 --- a/src/platform/Linux/InetPlatformConfig.h +++ b/src/platform/Linux/InetPlatformConfig.h @@ -36,6 +36,10 @@ #define INET_CONFIG_NUM_TCP_ENDPOINTS 32 #endif // INET_CONFIG_NUM_TCP_ENDPOINTS +#ifndef IPV6_MULTICAST_IMPLEMENTED +#define IPV6_MULTICAST_IMPLEMENTED +#endif + #ifndef INET_CONFIG_NUM_UDP_ENDPOINTS #define INET_CONFIG_NUM_UDP_ENDPOINTS 32 #endif // INET_CONFIG_NUM_UDP_ENDPOINTS diff --git a/src/transport/SessionManager.cpp b/src/transport/SessionManager.cpp index 87be4943ed0369..acfe8f24a53a79 100644 --- a/src/transport/SessionManager.cpp +++ b/src/transport/SessionManager.cpp @@ -195,25 +195,44 @@ CHIP_ERROR SessionManager::SendPreparedMessage(SessionHandle sessionHandle, cons if (sessionHandle.IsSecure()) { - // Find an active connection to the specified peer node - SecureSession * session = GetSecureSession(sessionHandle); - if (session == nullptr) + if (sessionHandle.IsGroupSession()) { - ChipLogError(Inet, "Secure transport could not find a valid PeerConnection"); - return CHIP_ERROR_NOT_CONNECTED; + chip::Transport::PeerAddress multicastAddress = + Transport::PeerAddress::Multicast(sessionHandle.GetFabricIndex(), sessionHandle.GetGroupId().Value()); + destination = static_cast(&multicastAddress); + char addressStr[Transport::PeerAddress::kMaxToStringSize]; + multicastAddress.ToString(addressStr, Transport::PeerAddress::kMaxToStringSize); + + ChipLogProgress(Inet, + "Sending %s msg %p with MessageCounter:" ChipLogFormatMessageCounter " to %d" + " at monotonic time: %" PRId64 + " msec to Multicast IPV6 address : %s with GroupID of %d and fabric Id of %d", + "encrypted", &preparedMessage, preparedMessage.GetMessageCounter(), sessionHandle.GetGroupId().Value(), + System::SystemClock().GetMonotonicMilliseconds64().count(), addressStr, + sessionHandle.GetGroupId().Value(), sessionHandle.GetFabricIndex()); } + else + { + // Find an active connection to the specified peer node + SecureSession * session = GetSecureSession(sessionHandle); + if (session == nullptr) + { + ChipLogError(Inet, "Secure transport could not find a valid PeerConnection"); + return CHIP_ERROR_NOT_CONNECTED; + } - // This marks any connection where we send data to as 'active' - mSecureSessions.MarkSessionActive(session); + // This marks any connection where we send data to as 'active' + mSecureSessions.MarkSessionActive(session); - destination = &session->GetPeerAddress(); + destination = &session->GetPeerAddress(); - ChipLogProgress(Inet, - "Sending %s msg %p with MessageCounter:" ChipLogFormatMessageCounter " to 0x" ChipLogFormatX64 - " (%u) at monotonic time: %" PRId64 " msec", - "encrypted", &preparedMessage, preparedMessage.GetMessageCounter(), - ChipLogValueX64(session->GetPeerNodeId()), session->GetFabricIndex(), - System::SystemClock().GetMonotonicMilliseconds64().count()); + ChipLogProgress(Inet, + "Sending %s msg %p with MessageCounter:" ChipLogFormatMessageCounter " to 0x" ChipLogFormatX64 + " (%u) at monotonic time: %" PRId64 " msec", + "encrypted", &preparedMessage, preparedMessage.GetMessageCounter(), + ChipLogValueX64(session->GetPeerNodeId()), session->GetFabricIndex(), + System::SystemClock().GetMonotonicMilliseconds64().count()); + } } else { diff --git a/src/transport/TransportMgrBase.cpp b/src/transport/TransportMgrBase.cpp index 0e393f14982c91..4b8c8752bdb355 100644 --- a/src/transport/TransportMgrBase.cpp +++ b/src/transport/TransportMgrBase.cpp @@ -50,6 +50,11 @@ void TransportMgrBase::Close() mTransport = nullptr; } +CHIP_ERROR TransportMgrBase::MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join) +{ + return mTransport->MulticastGroupJoinLeave(address, join); +} + void TransportMgrBase::HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) { if (msg->HasChainedBuffer()) diff --git a/src/transport/TransportMgrBase.h b/src/transport/TransportMgrBase.h index 2318e0bd684155..e4942ca6ecd90b 100644 --- a/src/transport/TransportMgrBase.h +++ b/src/transport/TransportMgrBase.h @@ -43,6 +43,8 @@ class TransportMgrBase : public Transport::RawTransportDelegate void SetSessionManager(TransportMgrDelegate * sessionManager) { mSessionManager = sessionManager; } + CHIP_ERROR MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join); + void HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) override; private: diff --git a/src/transport/raw/Base.h b/src/transport/raw/Base.h index d12be0ffe7992d..66c01a5fcc3d5d 100644 --- a/src/transport/raw/Base.h +++ b/src/transport/raw/Base.h @@ -72,11 +72,21 @@ class Base */ virtual bool CanSendToPeer(const PeerAddress & address) = 0; + /** + * Determine if this transport can Listen to IPV6 Multicast. + */ + virtual bool CanListenMulticast() { return false; } + /** * Handle disconnection from the specified peer if currently connected to it. */ virtual void Disconnect(const PeerAddress & address) {} + /** + * Enable Listening for multicast messages ( IPV6 UDP only) + */ + virtual CHIP_ERROR MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join) { return CHIP_ERROR_INTERNAL; } + /** * Close the open endpoint without destroying the object */ diff --git a/src/transport/raw/Tuple.h b/src/transport/raw/Tuple.h index 9cb7ab81c12382..f149c0dfde8871 100644 --- a/src/transport/raw/Tuple.h +++ b/src/transport/raw/Tuple.h @@ -86,6 +86,11 @@ class Tuple : public Base return SendMessageImpl<0>(address, std::move(msgBuf)); } + CHIP_ERROR MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join) override + { + return MulticastGroupJoinLeaveImpl<0>(address, join); + } + bool CanSendToPeer(const PeerAddress & address) override { return CanSendToPeerImpl<0>(address); } void Disconnect(const PeerAddress & address) override { return DisconnectImpl<0>(address); } @@ -203,6 +208,36 @@ class Tuple : public Base return CHIP_ERROR_NO_MESSAGE_HANDLER; } + /** + * Recursive GroupJoinLeave implementation iterating through transport members. + * + * Listener is activated through the first transport from index N or above, which returns 'CanListenMulticast' + * + * @tparam N the index of the underlying transport to run GroupJoinLeave through. + * + * @param address where to send the message + * @param msgBuf the message to send. Includes all CHIP message fields except optional length. + */ + template ::type * = nullptr> + CHIP_ERROR MulticastGroupJoinLeaveImpl(const Transport::PeerAddress & address, bool join) + { + Base * base = &std::get(mTransports); + if (base->CanListenMulticast()) + { + return base->MulticastGroupJoinLeave(address, join); + } + return MulticastGroupJoinLeaveImpl(address, join); + } + + /** + * GroupJoinLeave when N is out of range. Always returns an error code. + */ + template = sizeof...(TransportTypes))>::type * = nullptr> + CHIP_ERROR MulticastGroupJoinLeaveImpl(const Transport::PeerAddress & address, bool join) + { + return CHIP_ERROR_NO_MESSAGE_HANDLER; + } + /** * Recursive init implementation iterating through transport members * diff --git a/src/transport/raw/UDP.cpp b/src/transport/raw/UDP.cpp index af06e9c6b4ed92..d1d996fa6a2043 100644 --- a/src/transport/raw/UDP.cpp +++ b/src/transport/raw/UDP.cpp @@ -125,5 +125,22 @@ void UDP::OnUdpReceive(Inet::UDPEndPoint * endPoint, System::PacketBufferHandle } } +CHIP_ERROR UDP::MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join) +{ + char addressStr[Transport::PeerAddress::kMaxToStringSize]; + address.ToString(addressStr, Transport::PeerAddress::kMaxToStringSize); + + if (join) + { + ChipLogProgress(Inet, "Joining Multicast Group with address %s", addressStr); + return mUDPEndPoint->JoinMulticastGroup(mUDPEndPoint->GetBoundInterface(), address.GetIPAddress()); + } + else + { + ChipLogProgress(Inet, "Leaving Multicast Group with address %s", addressStr); + return mUDPEndPoint->LeaveMulticastGroup(mUDPEndPoint->GetBoundInterface(), address.GetIPAddress()); + } +} + } // namespace Transport } // namespace chip diff --git a/src/transport/raw/UDP.h b/src/transport/raw/UDP.h index c4951e80e40ec3..7aa554ffc6d6a1 100644 --- a/src/transport/raw/UDP.h +++ b/src/transport/raw/UDP.h @@ -115,6 +115,13 @@ class DLL_EXPORT UDP : public Base CHIP_ERROR SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf) override; + CHIP_ERROR MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join) override; + + bool CanListenMulticast() override + { + return (mState == State::kInitialized) && (mUDPEndpointType == Inet::IPAddressType::kIPv6); + } + bool CanSendToPeer(const Transport::PeerAddress & address) override { return (mState == State::kInitialized) && (address.GetTransportType() == Type::kUdp) &&