Skip to content

Commit 2581009

Browse files
kghostbzbarsky-apple
authored andcommitted
Add API to invalid sessions/exchanges for UpdateNOC command (#19328)
* Add API to invalid sessions/exchanges for UpdateNOC command * Complete the idea * Add purge all fabric API * Resolve comments: adjust function name * Restyle * Fix rebase conflict * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Resolve comments Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 8080bb1 commit 2581009

8 files changed

+98
-0
lines changed

src/messaging/ExchangeContext.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ ExchangeContext::~ExchangeContext()
325325
VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() == 0);
326326
VerifyOrDie(!IsAckPending());
327327

328+
if (ReleaseSessionOnDestruction() && mSession)
329+
mSession->AsSecureSession()->MarkForRemoval();
330+
328331
#if CONFIG_DEVICE_LAYER && CHIP_DEVICE_CONFIG_ENABLE_SED
329332
// Make sure that the exchange withdraws the request for Sleepy End Device active mode.
330333
UpdateSEDIntervalMode(false);

src/messaging/ExchangeMgr.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -376,5 +376,23 @@ void ExchangeManager::CloseAllContextsForDelegate(const ExchangeDelegate * deleg
376376
});
377377
}
378378

379+
void ExchangeManager::AbortExchangesForFabricExceptOne(FabricIndex fabricIndex, ExchangeContext * deferred)
380+
{
381+
VerifyOrDie(deferred->HasSessionHandle() && deferred->GetSessionHandle()->IsSecureSession());
382+
383+
mContextPool.ForEachActiveObject([&](auto * ec) {
384+
if (ec->HasSessionHandle() && ec->GetSessionHandle()->GetFabricIndex() == fabricIndex)
385+
{
386+
if (ec == deferred)
387+
ec->SetAutoReleaseSession();
388+
else
389+
ec->Abort();
390+
}
391+
return Loop::Continue;
392+
});
393+
394+
mSessionManager->ReleaseSessionsForFabricExceptOne(fabricIndex, deferred->GetSessionHandle());
395+
}
396+
379397
} // namespace Messaging
380398
} // namespace chip

src/messaging/ExchangeMgr.h

+5
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ class DLL_EXPORT ExchangeManager : public SessionMessageDelegate
183183
*/
184184
void CloseAllContextsForDelegate(const ExchangeDelegate * delegate);
185185

186+
// This API is used by commands that need to shut down all existing exchanges on a fabric but need to make sure the response to
187+
// the command still goes out on the exchange the command came in on. This API flags that one exchange to shut down its session
188+
// when it's done.
189+
void AbortExchangesForFabricExceptOne(FabricIndex fabricIndex, ExchangeContext * deferred);
190+
186191
SessionManager * GetSessionManager() const { return mSessionManager; }
187192

188193
ReliableMessageMgr * GetReliableMessageMgr() { return &mReliableMessageMgr; };

src/messaging/ReliableMessageContext.h

+18
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ class ReliableMessageContext
124124
/// Determine whether this exchange is a EphemeralExchange for replying a StandaloneAck
125125
bool IsEphemeralExchange() const;
126126

127+
// If SetAutoReleaseSession() is called, this exchange must be using a SecureSession, and should
128+
// evict it when the exchange is done with all its work (including any MRP traffic).
129+
void SetAutoReleaseSession();
130+
bool ReleaseSessionOnDestruction();
131+
127132
/**
128133
* Get the reliable message manager that corresponds to this reliable
129134
* message context.
@@ -164,6 +169,9 @@ class ReliableMessageContext
164169

165170
/// When set, signifies that the exchange created sorely for replying a StandaloneAck
166171
kFlagEphemeralExchange = (1u << 9),
172+
173+
/// When set, automatically release the session when this exchange is destroyed.
174+
kFlagAutoReleaseSession = (1u << 10),
167175
};
168176

169177
BitFlags<Flags> mFlags; // Internal state flags
@@ -245,5 +253,15 @@ inline bool ReliableMessageContext::IsEphemeralExchange() const
245253
return mFlags.Has(Flags::kFlagEphemeralExchange);
246254
}
247255

256+
inline void ReliableMessageContext::SetAutoReleaseSession()
257+
{
258+
mFlags.Set(Flags::kFlagAutoReleaseSession, true);
259+
}
260+
261+
inline bool ReliableMessageContext::ReleaseSessionOnDestruction()
262+
{
263+
return mFlags.Has(Flags::kFlagAutoReleaseSession);
264+
}
265+
248266
} // namespace Messaging
249267
} // namespace chip

src/transport/SecureSession.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void SecureSession::MarkForRemoval()
3939
NotifySessionReleased();
4040
return;
4141
case State::kActive:
42+
case State::kInactive:
4243
Release(); // Decrease the ref which is retained at Activate
4344
mState = State::kPendingRemoval;
4445
NotifySessionReleased();
@@ -49,6 +50,27 @@ void SecureSession::MarkForRemoval()
4950
}
5051
}
5152

53+
void SecureSession::MarkInactive()
54+
{
55+
ChipLogDetail(Inet, "SecureSession[%p]: MarkInactive Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
56+
mLocalSessionId);
57+
ReferenceCountedHandle<Transport::Session> ref(*this);
58+
switch (mState)
59+
{
60+
case State::kPairing:
61+
VerifyOrDie(false);
62+
return;
63+
case State::kActive:
64+
// By setting this state, IsActiveSession() will return false, which prevents creating new exchanges.
65+
mState = State::kInactive;
66+
return;
67+
case State::kInactive:
68+
case State::kPendingRemoval:
69+
// Do nothing
70+
return;
71+
}
72+
}
73+
5274
Access::SubjectDescriptor SecureSession::GetSubjectDescriptor() const
5375
{
5476
Access::SubjectDescriptor subjectDescriptor;

src/transport/SecureSession.h

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class SecureSession : public Session, public ReferenceCounted<SecureSession, Sec
144144
/// @brief Mark as pending removal, all holders to this session will be cleared, and disallow future grab
145145
void MarkForRemoval();
146146

147+
// Used to prevent any new exchange created on the session while the existing exchanges finish their work.
148+
void MarkInactive();
149+
147150
Session::SessionType GetSessionType() const override { return Session::SessionType::kSecure; }
148151
#if CHIP_PROGRESS_LOGGING
149152
const char * GetSessionTypeString() const override { return "secure"; };
@@ -249,6 +252,13 @@ class SecureSession : public Session, public ReferenceCounted<SecureSession, Sec
249252
// grab this session, when all SessionHandles go out of scope, the
250253
// session object will be released automatically.
251254
kPendingRemoval = 3,
255+
256+
// The session is still functional, but it can't yield any new exchanges,
257+
// This is meant to be used in conjunction with
258+
// ExchangeManager::AbortExchangesForFabricExceptOne, with the one
259+
// exceptional exchange handling moving this session out of this state when
260+
// it finishes whatever it needs the session for.
261+
kInactive = 4,
252262
};
253263

254264
friend class SecureSessionDeleter;

src/transport/SessionManager.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,23 @@ void SessionManager::ExpireAllPASEPairings()
387387
});
388388
}
389389

390+
void SessionManager::ReleaseSessionsForFabricExceptOne(FabricIndex fabricIndex, const SessionHandle & deferred)
391+
{
392+
VerifyOrDie(deferred->IsSecureSession());
393+
SecureSession * deferredSecureSession = deferred->AsSecureSession();
394+
395+
mSecureSessions.ForEachSession([&](auto session) {
396+
if (session->GetPeer().GetFabricIndex() == fabricIndex)
397+
{
398+
if (session == deferredSecureSession)
399+
session->MarkInactive();
400+
else
401+
session->MarkForRemoval();
402+
}
403+
return Loop::Continue;
404+
});
405+
}
406+
390407
Optional<SessionHandle> SessionManager::AllocateSession(SecureSession::Type secureSessionType,
391408
const ScopedNodeId & sessionEvictionHint)
392409
{

src/transport/SessionManager.h

+5
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate
176176
void ExpireAllPairingsForFabric(FabricIndex fabric);
177177
void ExpireAllPASEPairings();
178178

179+
// This API is used by commands that need to release all existing sessions on a fabric but need to make sure the response to the
180+
// command still goes out on the exchange the command came in on. This API flags that the release of the session used by the
181+
// exchange is deferred until the exchange is done.
182+
void ReleaseSessionsForFabricExceptOne(FabricIndex fabricIndex, const SessionHandle & deferred);
183+
179184
/**
180185
* @brief
181186
* Return the System Layer pointer used by current SessionManager.

0 commit comments

Comments
 (0)