Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2023 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <app/InteractionModelEngine.h>
19 : #include <app/SubscriptionResumptionSessionEstablisher.h>
20 :
21 : namespace chip {
22 : namespace app {
23 :
24 : class AutoDeleteEstablisher
25 : {
26 : public:
27 0 : AutoDeleteEstablisher(SubscriptionResumptionSessionEstablisher * sessionEstablisher) : mSessionEstablisher(sessionEstablisher)
28 0 : {}
29 0 : ~AutoDeleteEstablisher() { chip::Platform::Delete(mSessionEstablisher); }
30 :
31 0 : SubscriptionResumptionSessionEstablisher * operator->() const { return mSessionEstablisher; }
32 :
33 0 : SubscriptionResumptionSessionEstablisher & operator*() const { return *mSessionEstablisher; }
34 :
35 : private:
36 : SubscriptionResumptionSessionEstablisher * mSessionEstablisher;
37 : };
38 :
39 0 : SubscriptionResumptionSessionEstablisher::SubscriptionResumptionSessionEstablisher() :
40 0 : mOnConnectedCallback(HandleDeviceConnected, this), mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this)
41 0 : {}
42 :
43 : CHIP_ERROR
44 0 : SubscriptionResumptionSessionEstablisher::ResumeSubscription(
45 : CASESessionManager & caseSessionManager, const SubscriptionResumptionStorage::SubscriptionInfo & subscriptionInfo)
46 : {
47 0 : mSubscriptionInfo.mNodeId = subscriptionInfo.mNodeId;
48 0 : mSubscriptionInfo.mFabricIndex = subscriptionInfo.mFabricIndex;
49 0 : mSubscriptionInfo.mSubscriptionId = subscriptionInfo.mSubscriptionId;
50 0 : mSubscriptionInfo.mMinInterval = subscriptionInfo.mMinInterval;
51 0 : mSubscriptionInfo.mMaxInterval = subscriptionInfo.mMaxInterval;
52 0 : mSubscriptionInfo.mFabricFiltered = subscriptionInfo.mFabricFiltered;
53 : #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
54 0 : mSubscriptionInfo.mResumptionRetries = subscriptionInfo.mResumptionRetries;
55 : #endif
56 : // Copy the Attribute Paths and Event Paths
57 0 : if (subscriptionInfo.mAttributePaths.AllocatedSize() > 0)
58 : {
59 0 : mSubscriptionInfo.mAttributePaths.Alloc(subscriptionInfo.mAttributePaths.AllocatedSize());
60 0 : if (!mSubscriptionInfo.mAttributePaths.Get())
61 : {
62 0 : return CHIP_ERROR_NO_MEMORY;
63 : }
64 0 : for (size_t i = 0; i < mSubscriptionInfo.mAttributePaths.AllocatedSize(); ++i)
65 : {
66 0 : mSubscriptionInfo.mAttributePaths[i] = subscriptionInfo.mAttributePaths[i];
67 : }
68 : }
69 0 : if (subscriptionInfo.mEventPaths.AllocatedSize() > 0)
70 : {
71 0 : mSubscriptionInfo.mEventPaths.Alloc(subscriptionInfo.mEventPaths.AllocatedSize());
72 0 : if (!mSubscriptionInfo.mEventPaths.Get())
73 : {
74 0 : return CHIP_ERROR_NO_MEMORY;
75 : }
76 0 : for (size_t i = 0; i < mSubscriptionInfo.mEventPaths.AllocatedSize(); ++i)
77 : {
78 0 : mSubscriptionInfo.mEventPaths[i] = subscriptionInfo.mEventPaths[i];
79 : }
80 : }
81 :
82 0 : ScopedNodeId peerNode = ScopedNodeId(mSubscriptionInfo.mNodeId, mSubscriptionInfo.mFabricIndex);
83 0 : caseSessionManager.FindOrEstablishSession(peerNode, &mOnConnectedCallback, &mOnConnectionFailureCallback);
84 0 : return CHIP_NO_ERROR;
85 : }
86 :
87 0 : void SubscriptionResumptionSessionEstablisher::HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr,
88 : const SessionHandle & sessionHandle)
89 : {
90 0 : AutoDeleteEstablisher establisher(static_cast<SubscriptionResumptionSessionEstablisher *>(context));
91 0 : SubscriptionResumptionStorage::SubscriptionInfo & subscriptionInfo = establisher->mSubscriptionInfo;
92 0 : InteractionModelEngine * imEngine = InteractionModelEngine::GetInstance();
93 :
94 : // Decrement the number of subscriptions to resume since we have completed our retry attempt for a given subscription.
95 : // We do this before the readHandler creation since we do not care if the subscription has successfully been resumed or
96 : // not. Counter only tracks the number of individual subscriptions we will try to resume.
97 0 : imEngine->DecrementNumSubscriptionsToResume();
98 :
99 0 : if (!imEngine->EnsureResourceForSubscription(subscriptionInfo.mFabricIndex, subscriptionInfo.mAttributePaths.AllocatedSize(),
100 : subscriptionInfo.mEventPaths.AllocatedSize()))
101 : {
102 : // TODO - Should we keep the subscription here?
103 0 : ChipLogProgress(InteractionModel, "no resource for subscription resumption");
104 0 : return;
105 : }
106 : ReadHandler * readHandler =
107 0 : imEngine->mReadHandlers.CreateObject(*imEngine, imEngine->GetReportScheduler(), imEngine->GetDataModelProvider());
108 0 : if (readHandler == nullptr)
109 : {
110 : // TODO - Should we keep the subscription here?
111 0 : ChipLogProgress(InteractionModel, "no resource for ReadHandler creation");
112 0 : return;
113 : }
114 0 : readHandler->OnSubscriptionResumed(sessionHandle, *establisher);
115 : #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
116 : // Reset the resumption retries to 0 if subscription is resumed
117 0 : subscriptionInfo.mResumptionRetries = 0;
118 0 : auto * subscriptionResumptionStorage = InteractionModelEngine::GetInstance()->GetSubscriptionResumptionStorage();
119 0 : if (subscriptionResumptionStorage)
120 : {
121 0 : subscriptionResumptionStorage->Save(subscriptionInfo);
122 : }
123 : #endif // CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
124 0 : }
125 :
126 0 : void SubscriptionResumptionSessionEstablisher::HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId,
127 : CHIP_ERROR error)
128 : {
129 0 : AutoDeleteEstablisher establisher(static_cast<SubscriptionResumptionSessionEstablisher *>(context));
130 0 : InteractionModelEngine * imEngine = InteractionModelEngine::GetInstance();
131 0 : SubscriptionResumptionStorage::SubscriptionInfo & subscriptionInfo = establisher->mSubscriptionInfo;
132 0 : ChipLogError(DataManagement, "Failed to establish CASE for subscription-resumption with error '%" CHIP_ERROR_FORMAT "'",
133 : error.Format());
134 :
135 : // Decrement the number of subscriptions to resume since we have completed our retry attempt for a given subscription.
136 : // We do this here since we were not able to connect to the subscriber thus we have completed our resumption attempt.
137 : // Counter only tracks the number of individual subscriptions we will try to resume.
138 0 : imEngine->DecrementNumSubscriptionsToResume();
139 :
140 0 : auto * subscriptionResumptionStorage = imEngine->GetSubscriptionResumptionStorage();
141 0 : if (!subscriptionResumptionStorage)
142 : {
143 0 : ChipLogError(DataManagement, "Failed to get subscription resumption storage");
144 0 : return;
145 : }
146 : #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
147 0 : if (subscriptionInfo.mResumptionRetries <= CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION_MAX_FIBONACCI_STEP_INDEX)
148 : {
149 0 : InteractionModelEngine::GetInstance()->TryToResumeSubscriptions();
150 0 : subscriptionInfo.mResumptionRetries++;
151 0 : subscriptionResumptionStorage->Save(subscriptionInfo);
152 : }
153 : else
154 : #endif // CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
155 : {
156 : // If the device fails to establish the session several times, the subscriber might be offline and its subscription
157 : // read client will be deleted when the device reconnects to the subscriber. This subscription will be never used again.
158 : // Clean up the persistent subscription information storage.
159 0 : subscriptionResumptionStorage->Delete(subscriptionInfo.mNodeId, subscriptionInfo.mFabricIndex,
160 : subscriptionInfo.mSubscriptionId);
161 : }
162 0 : }
163 :
164 : } // namespace app
165 : } // namespace chip
|