Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include <app/CASESessionManager.h>
20 : #include <lib/address_resolve/AddressResolve.h>
21 :
22 : namespace chip {
23 :
24 1 : CHIP_ERROR CASESessionManager::Init(chip::System::Layer * systemLayer, const CASESessionManagerConfig & params)
25 : {
26 1 : ReturnErrorOnFailure(params.sessionInitParams.Validate());
27 1 : mConfig = params;
28 1 : params.sessionInitParams.exchangeMgr->GetReliableMessageMgr()->RegisterSessionUpdateDelegate(this);
29 1 : return AddressResolve::Resolver::Instance().Init(systemLayer);
30 : }
31 :
32 1 : void CASESessionManager::Shutdown()
33 : {
34 1 : AddressResolve::Resolver::Instance().Shutdown();
35 1 : }
36 :
37 0 : void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
38 : Callback::Callback<OnDeviceConnectionFailure> * onFailure,
39 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
40 : uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry,
41 : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
42 : TransportPayloadCapability transportPayloadCapability,
43 : const Optional<AddressResolve::ResolveResult> & fallbackResolveResult)
44 : {
45 0 : FindOrEstablishSessionHelper(peerId, onConnection, onFailure, nullptr,
46 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
47 : attemptCount, onRetry,
48 : #endif
49 : transportPayloadCapability, fallbackResolveResult);
50 0 : }
51 :
52 0 : void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
53 : Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure,
54 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
55 : uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry,
56 : #endif
57 : TransportPayloadCapability transportPayloadCapability)
58 : {
59 0 : FindOrEstablishSessionHelper(peerId, onConnection, nullptr, onSetupFailure,
60 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
61 : attemptCount, onRetry,
62 : #endif
63 : transportPayloadCapability);
64 0 : }
65 :
66 0 : void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
67 : std::nullptr_t,
68 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
69 : uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry,
70 : #endif
71 : TransportPayloadCapability transportPayloadCapability)
72 : {
73 0 : FindOrEstablishSessionHelper(peerId, onConnection, nullptr, nullptr,
74 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
75 : attemptCount, onRetry,
76 : #endif
77 : transportPayloadCapability);
78 0 : }
79 :
80 0 : void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
81 : Callback::Callback<OnDeviceConnectionFailure> * onFailure,
82 : TransportPayloadCapability transportPayloadCapability)
83 : {
84 0 : FindOrEstablishSessionHelper(peerId, onConnection, onFailure, nullptr,
85 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
86 : 1 /* attemptCount */, nullptr /* onRetry */,
87 : #endif
88 : transportPayloadCapability);
89 0 : }
90 :
91 0 : void CASESessionManager::FindOrEstablishSessionHelper(const ScopedNodeId & peerId,
92 : Callback::Callback<OnDeviceConnected> * onConnection,
93 : Callback::Callback<OnDeviceConnectionFailure> * onFailure,
94 : Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure,
95 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
96 : uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry,
97 : #endif
98 : TransportPayloadCapability transportPayloadCapability,
99 : const Optional<AddressResolve::ResolveResult> & fallbackResolveResult)
100 : {
101 0 : ChipLogDetail(CASESessionManager, "FindOrEstablishSession: PeerId = [%d:" ChipLogFormatX64 "]", peerId.GetFabricIndex(),
102 : ChipLogValueX64(peerId.GetNodeId()));
103 :
104 0 : bool forAddressUpdate = false;
105 0 : OperationalSessionSetup * session = FindExistingSessionSetup(peerId, forAddressUpdate);
106 0 : if (session == nullptr)
107 : {
108 0 : ChipLogDetail(CASESessionManager, "FindOrEstablishSession: No existing OperationalSessionSetup instance found");
109 0 : session = mConfig.sessionSetupPool->Allocate(mConfig.sessionInitParams, mConfig.clientPool, peerId, this);
110 :
111 0 : if (session == nullptr)
112 : {
113 0 : if (onFailure != nullptr)
114 : {
115 0 : onFailure->mCall(onFailure->mContext, peerId, CHIP_ERROR_NO_MEMORY);
116 : }
117 :
118 0 : if (onSetupFailure != nullptr)
119 : {
120 : OperationalSessionSetup::ConnectionFailureInfo failureInfo(peerId, CHIP_ERROR_NO_MEMORY,
121 0 : SessionEstablishmentStage::kUnknown);
122 0 : onSetupFailure->mCall(onSetupFailure->mContext, failureInfo);
123 : }
124 0 : return;
125 : }
126 : }
127 :
128 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
129 0 : session->UpdateAttemptCount(attemptCount);
130 0 : if (onRetry)
131 : {
132 0 : session->AddRetryHandler(onRetry);
133 : }
134 : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
135 :
136 : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
137 : // Set fallback resolve result if provided
138 : if (fallbackResolveResult.HasValue())
139 : {
140 : session->SetFallbackResolveResult(fallbackResolveResult.Value());
141 : }
142 : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
143 :
144 0 : if (onFailure != nullptr)
145 : {
146 0 : session->Connect(onConnection, onFailure, transportPayloadCapability);
147 : }
148 :
149 0 : if (onSetupFailure != nullptr)
150 : {
151 0 : session->Connect(onConnection, onSetupFailure, transportPayloadCapability);
152 : }
153 : }
154 :
155 1 : void CASESessionManager::ReleaseSessionsForFabric(FabricIndex fabricIndex)
156 : {
157 : // Intentionally bypasses the IsEstablishingSession() in-flight guard used by
158 : // ReleaseSession(peerId). Fabric removal is irreversible; all setups for the fabric
159 : // -- including mid-handshake ones -- must be torn down unconditionally to avoid
160 : // dangling references to a removed fabric.
161 1 : mConfig.sessionSetupPool->ReleaseAllSessionSetupsForFabric(fabricIndex);
162 1 : }
163 :
164 1 : void CASESessionManager::ReleaseAllSessions()
165 : {
166 : // Intentionally bypasses the IsEstablishingSession() in-flight guard used by
167 : // ReleaseSession(peerId). Shutdown is terminal; every setup must be destroyed
168 : // regardless of handshake state. Safe because the caller is tearing down the entire
169 : // stack, not trimming individual peers.
170 1 : mConfig.sessionSetupPool->ReleaseAllSessionSetup();
171 1 : }
172 :
173 0 : CHIP_ERROR CASESessionManager::GetPeerAddress(const ScopedNodeId & peerId, Transport::PeerAddress & addr,
174 : TransportPayloadCapability transportPayloadCapability)
175 : {
176 0 : ReturnErrorOnFailure(mConfig.sessionInitParams.Validate());
177 0 : auto optionalSessionHandle = FindExistingSession(peerId, transportPayloadCapability);
178 0 : VerifyOrReturnError(optionalSessionHandle.HasValue(), CHIP_ERROR_NOT_CONNECTED);
179 0 : addr = optionalSessionHandle.Value()->AsSecureSession()->GetPeerAddress();
180 0 : return CHIP_NO_ERROR;
181 0 : }
182 :
183 0 : void CASESessionManager::UpdatePeerAddress(ScopedNodeId peerId)
184 : {
185 0 : bool forAddressUpdate = true;
186 0 : OperationalSessionSetup * session = FindExistingSessionSetup(peerId, forAddressUpdate);
187 0 : if (session == nullptr)
188 : {
189 0 : ChipLogDetail(CASESessionManager, "UpdatePeerAddress: No existing OperationalSessionSetup instance found");
190 :
191 0 : session = mConfig.sessionSetupPool->Allocate(mConfig.sessionInitParams, mConfig.clientPool, peerId, this);
192 0 : if (session == nullptr)
193 : {
194 0 : ChipLogDetail(CASESessionManager, "UpdatePeerAddress: Failed to allocate OperationalSessionSetup instance");
195 0 : return;
196 : }
197 : }
198 : else
199 : {
200 0 : ChipLogDetail(CASESessionManager,
201 : "UpdatePeerAddress: Found existing OperationalSessionSetup instance for peerId[" ChipLogFormatX64 "]",
202 : ChipLogValueX64(peerId.GetNodeId()));
203 : }
204 :
205 0 : session->PerformAddressUpdate();
206 : }
207 :
208 0 : OperationalSessionSetup * CASESessionManager::FindExistingSessionSetup(const ScopedNodeId & peerId, bool forAddressUpdate) const
209 : {
210 0 : return mConfig.sessionSetupPool->FindSessionSetup(peerId, forAddressUpdate);
211 : }
212 :
213 0 : Optional<SessionHandle> CASESessionManager::FindExistingSession(const ScopedNodeId & peerId,
214 : const TransportPayloadCapability transportPayloadCapability) const
215 : {
216 0 : return mConfig.sessionInitParams.sessionManager->FindSecureSessionForNode(
217 0 : peerId, MakeOptional(Transport::SecureSession::Type::kCASE), transportPayloadCapability);
218 : }
219 :
220 22 : void CASESessionManager::ReleaseSession(const ScopedNodeId & peerId)
221 : {
222 22 : auto * session = mConfig.sessionSetupPool->FindSessionSetup(peerId, false);
223 22 : if (session != nullptr && session->IsEstablishingSession())
224 : {
225 : // Don't tear down a setup that's actively trying to establish.
226 : // The OperationalSessionSetup owns retry state (mAttemptsDone,
227 : // mRequestedBusyDelay, exponential backoff); destroying it resets
228 : // that state and produces a churn of fresh Sigma1 attempts against
229 : // a slow/busy accessory each time a higher layer
230 : // calls ReleaseSession during cold-start.
231 : // Let the in-flight attempt complete or hit its own retry cycle
232 : // naturally.
233 17 : ChipLogDetail(Discovery,
234 : "CASESessionManager::ReleaseSession for " ChipLogFormatScopedNodeId
235 : ": setup is establishing a session, skipping release",
236 : ChipLogValueScopedNodeId(peerId));
237 17 : return;
238 : }
239 5 : ReleaseSession(session);
240 : }
241 :
242 5 : void CASESessionManager::ReleaseSession(OperationalSessionSetup * session)
243 : {
244 : // OperationalSessionReleaseDelegate override. No IsEstablishingSession() guard here:
245 : // this overload's only callers are (1) OperationalSessionSetup itself, requesting
246 : // self-destruction after its handshake has finished (success or terminal failure)
247 : // -- by which point the setup is no longer "establishing" -- and (2) the peerId
248 : // overload above, which has already applied the guard. A check here would be
249 : // redundant with (2) and incorrect for (1), since (1) needs the release to happen.
250 5 : if (session != nullptr)
251 : {
252 4 : mConfig.sessionSetupPool->Release(session);
253 : }
254 5 : }
255 :
256 : } // namespace chip
|