Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to invalid sessions/exchanges for UpdateNOC command #19328

Merged
merged 8 commits into from
Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ ExchangeContext::~ExchangeContext()
VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() == 0);
VerifyOrDie(!IsAckPending());

if (ReleaseSessionOnDestruction() && mSession)
mSession->AsSecureSession()->MarkForRemoval();

#if CONFIG_DEVICE_LAYER && CHIP_DEVICE_CONFIG_ENABLE_SED
// Make sure that the exchange withdraws the request for Sleepy End Device active mode.
UpdateSEDIntervalMode(false);
Expand Down
18 changes: 18 additions & 0 deletions src/messaging/ExchangeMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,5 +376,23 @@ void ExchangeManager::CloseAllContextsForDelegate(const ExchangeDelegate * deleg
});
}

void ExchangeManager::AbortExchangesForFabricExceptOne(FabricIndex fabricIndex, ExchangeContext * deferred)
{
VerifyOrDie(deferred->HasSessionHandle() && deferred->GetSessionHandle()->IsSecureSession());

mContextPool.ForEachActiveObject([&](auto * ec) {
if (ec->HasSessionHandle() && ec->GetSessionHandle()->GetFabricIndex() == fabricIndex)
{
if (ec == deferred)
ec->SetAutoReleaseSession();
else
ec->Abort();
kghost marked this conversation as resolved.
Show resolved Hide resolved
}
return Loop::Continue;
});

mSessionManager->ReleaseSessionsForFabricExceptOne(fabricIndex, deferred->GetSessionHandle());
}

} // namespace Messaging
} // namespace chip
5 changes: 5 additions & 0 deletions src/messaging/ExchangeMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ class DLL_EXPORT ExchangeManager : public SessionMessageDelegate
*/
void CloseAllContextsForDelegate(const ExchangeDelegate * delegate);

// 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
// the command still goes out on the exchange the command came in on. This API flags that one exchange to shut down its session
// when it's done.
void AbortExchangesForFabricExceptOne(FabricIndex fabricIndex, ExchangeContext * deferred);

SessionManager * GetSessionManager() const { return mSessionManager; }

ReliableMessageMgr * GetReliableMessageMgr() { return &mReliableMessageMgr; };
Expand Down
18 changes: 18 additions & 0 deletions src/messaging/ReliableMessageContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ class ReliableMessageContext
/// Determine whether this exchange is a EphemeralExchange for replying a StandaloneAck
bool IsEphemeralExchange() const;

// If SetAutoReleaseSession() is called, this exchange must be using a SecureSession, and should
// evict it when the exchange is done with all its work (including any MRP traffic).
void SetAutoReleaseSession();
bool ReleaseSessionOnDestruction();

/**
* Get the reliable message manager that corresponds to this reliable
* message context.
Expand Down Expand Up @@ -164,6 +169,9 @@ class ReliableMessageContext

/// When set, signifies that the exchange created sorely for replying a StandaloneAck
kFlagEphemeralExchange = (1u << 9),

/// When set, automatically release the session when this exchange is destroyed.
kFlagAutoReleaseSession = (1u << 10),
};

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

inline void ReliableMessageContext::SetAutoReleaseSession()
{
mFlags.Set(Flags::kFlagAutoReleaseSession, true);
}

inline bool ReliableMessageContext::ReleaseSessionOnDestruction()
{
return mFlags.Has(Flags::kFlagAutoReleaseSession);
}

} // namespace Messaging
} // namespace chip
22 changes: 22 additions & 0 deletions src/transport/SecureSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void SecureSession::MarkForRemoval()
NotifySessionReleased();
return;
case State::kActive:
case State::kInactive:
Release(); // Decrease the ref which is retained at Activate
mState = State::kPendingRemoval;
NotifySessionReleased();
Expand All @@ -49,6 +50,27 @@ void SecureSession::MarkForRemoval()
}
}

void SecureSession::MarkInactive()
{
ChipLogDetail(Inet, "SecureSession[%p]: MarkInactive Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
mLocalSessionId);
ReferenceCountedHandle<Transport::Session> ref(*this);
switch (mState)
{
case State::kPairing:
VerifyOrDie(false);
return;
case State::kActive:
// By setting this state, IsActiveSession() will return false, which prevents creating new exchanges.
mState = State::kInactive;
return;
case State::kInactive:
case State::kPendingRemoval:
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
// Do nothing
return;
}
}

Access::SubjectDescriptor SecureSession::GetSubjectDescriptor() const
{
Access::SubjectDescriptor subjectDescriptor;
Expand Down
10 changes: 10 additions & 0 deletions src/transport/SecureSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class SecureSession : public Session, public ReferenceCounted<SecureSession, Sec
/// @brief Mark as pending removal, all holders to this session will be cleared, and disallow future grab
void MarkForRemoval();

// Used to prevent any new exchange created on the session while the existing exchanges finish their work.
void MarkInactive();

Session::SessionType GetSessionType() const override { return Session::SessionType::kSecure; }
#if CHIP_PROGRESS_LOGGING
const char * GetSessionTypeString() const override { return "secure"; };
Expand Down Expand Up @@ -249,6 +252,13 @@ class SecureSession : public Session, public ReferenceCounted<SecureSession, Sec
// grab this session, when all SessionHandles go out of scope, the
// session object will be released automatically.
kPendingRemoval = 3,

// The session is still functional, but it can't yield any new exchanges,
// This is meant to be used in conjunction with
// ExchangeManager::AbortExchangesForFabricExceptOne, with the one
// exceptional exchange handling moving this session out of this state when
// it finishes whatever it needs the session for.
kInactive = 4,
kghost marked this conversation as resolved.
Show resolved Hide resolved
};

friend class SecureSessionDeleter;
Expand Down
17 changes: 17 additions & 0 deletions src/transport/SessionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,23 @@ void SessionManager::ExpireAllPASEPairings()
});
}

void SessionManager::ReleaseSessionsForFabricExceptOne(FabricIndex fabricIndex, const SessionHandle & deferred)
kghost marked this conversation as resolved.
Show resolved Hide resolved
{
VerifyOrDie(deferred->IsSecureSession());
SecureSession * deferredSecureSession = deferred->AsSecureSession();

mSecureSessions.ForEachSession([&](auto session) {
if (session->GetPeer().GetFabricIndex() == fabricIndex)
{
if (session == deferredSecureSession)
session->MarkInactive();
else
session->MarkForRemoval();
}
return Loop::Continue;
});
}

Optional<SessionHandle> SessionManager::AllocateSession(SecureSession::Type secureSessionType,
const ScopedNodeId & sessionEvictionHint)
{
Expand Down
5 changes: 5 additions & 0 deletions src/transport/SessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate
void ExpireAllPairingsForFabric(FabricIndex fabric);
void ExpireAllPASEPairings();

// 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
// command still goes out on the exchange the command came in on. This API flags that the release of the session used by the
// exchange is deferred until the exchange is done.
void ReleaseSessionsForFabricExceptOne(FabricIndex fabricIndex, const SessionHandle & deferred);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief
* Return the System Layer pointer used by current SessionManager.
Expand Down