Skip to content

Commit

Permalink
StandaloneAck handling: Untangle code path for UMH and StandaloneAck
Browse files Browse the repository at this point in the history
  • Loading branch information
kghost committed Jun 10, 2022
1 parent fa18784 commit 58917eb
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 31 deletions.
23 changes: 21 additions & 2 deletions src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <messaging/ApplicationExchangeDispatch.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeMgr.h>
#include <messaging/StandaloneExchangeDispatch.h>
#include <protocols/Protocols.h>
#include <protocols/secure_channel/Constants.h>

Expand Down Expand Up @@ -290,8 +291,8 @@ void ExchangeContextDeletor::Release(ExchangeContext * ec)
}

ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, const SessionHandle & session, bool Initiator,
ExchangeDelegate * delegate) :
mDispatch((delegate != nullptr) ? delegate->GetMessageDispatch() : ApplicationExchangeDispatch::Instance()),
ExchangeDelegate * delegate, bool isStandaloneExchange) :
mDispatch(GetMessageDispatch(isStandaloneExchange, delegate)),
mSession(*this)
{
VerifyOrDie(mExchangeMgr == nullptr);
Expand All @@ -300,6 +301,7 @@ ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, cons
mExchangeId = ExchangeId;
mSession.Grab(session);
mFlags.Set(Flags::kFlagInitiator, Initiator);
mFlags.Set(Flags::kFlagStandaloneExchange, isStandaloneExchange);
mDelegate = delegate;

SetAckPending(false);
Expand Down Expand Up @@ -494,6 +496,12 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
return CHIP_NO_ERROR;
}

if (IsStandaloneExchange())
{
// The StandaloneExchange has done its job, since StandaloneAck is sent in previous FlushAcks() call.
return CHIP_NO_ERROR;
}

// Since we got the response, cancel the response timer.
CancelResponseTimer();

Expand Down Expand Up @@ -527,5 +535,16 @@ void ExchangeContext::MessageHandled()
Close();
}

ExchangeMessageDispatch & ExchangeContext::GetMessageDispatch(bool isStandaloneExchange, ExchangeDelegate * delegate)
{
if (isStandaloneExchange)
return StandaloneExchangeDispatch::Instance();

if (delegate != nullptr)
return delegate->GetMessageDispatch();

return ApplicationExchangeDispatch::Instance();
}

} // namespace Messaging
} // namespace chip
6 changes: 3 additions & 3 deletions src/messaging/ExchangeContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
typedef System::Clock::Timeout Timeout; // Type used to express the timeout in this ExchangeContext

ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, const SessionHandle & session, bool Initiator,
ExchangeDelegate * delegate);
ExchangeDelegate * delegate, bool isStandaloneExchange = false);

~ExchangeContext() override;

Expand Down Expand Up @@ -154,8 +154,6 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,

ReliableMessageContext * GetReliableMessageContext() { return static_cast<ReliableMessageContext *>(this); };

ExchangeMessageDispatch & GetMessageDispatch() { return mDispatch; }

SessionHandle GetSessionHandle() const
{
VerifyOrDie(mSession);
Expand Down Expand Up @@ -273,6 +271,8 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
* exchange nor other component requests the active mode.
*/
void UpdateSEDIntervalMode(bool activeMode);

static ExchangeMessageDispatch & GetMessageDispatch(bool isStandaloneExchange, ExchangeDelegate * delegate);
};

} // namespace Messaging
Expand Down
72 changes: 46 additions & 26 deletions src/messaging/ExchangeMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,22 +270,18 @@ void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const
return;
}

// If we found a handler or we need to send an ack, create an exchange to
// handle the message.
if (matchingUMH != nullptr || payloadHeader.NeedsAck())
// If we found a handler, create an exchange to handle the message.
if (matchingUMH != nullptr)
{
ExchangeDelegate * delegate = nullptr;

// Fetch delegate from the handler
if (matchingUMH != nullptr)
CHIP_ERROR err = matchingUMH->Handler->OnUnsolicitedMessageReceived(payloadHeader, delegate);
if (err != CHIP_NO_ERROR)
{
CHIP_ERROR err = matchingUMH->Handler->OnUnsolicitedMessageReceived(payloadHeader, delegate);
if (err != CHIP_NO_ERROR)
{
// Using same error message for all errors to reduce code size.
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(err));
return;
}
// Using same error message for all errors to reduce code size.
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(err));
return;
}

// If rcvd msg is from initiator then this exchange is created as not Initiator.
Expand All @@ -297,7 +293,7 @@ void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const

if (ec == nullptr)
{
if (matchingUMH != nullptr && delegate != nullptr)
if (delegate != nullptr)
{
matchingUMH->Handler->OnExchangeCreationFailed(delegate);
}
Expand All @@ -310,31 +306,55 @@ void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const
ChipLogDetail(ExchangeManager, "Handling via exchange: " ChipLogFormatExchange ", Delegate: %p", ChipLogValueExchange(ec),
ec->GetDelegate());

if (ec->IsEncryptionRequired() != packetHeader.IsEncrypted())
{
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(CHIP_ERROR_INVALID_MESSAGE_TYPE));
ec->Close();
return;
}

err = ec->HandleMessage(packetHeader.GetMessageCounter(), payloadHeader, msgFlags, std::move(msgBuf));
if (err != CHIP_NO_ERROR)
{
// Using same error message for all errors to reduce code size.
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(err));
}
return;
}

// If we need to send a StandaloneAck, create a StandaloneExchange for the purpose to send the StandaloneAck
if (payloadHeader.NeedsAck())
{
// If rcvd msg is from initiator then this exchange is created as not Initiator.
// If rcvd msg is not from initiator then this exchange is created as Initiator.
// Create a StandaloneExchange to generate a StandaloneAck
ExchangeContext * ec = mContextPool.CreateObject(this, payloadHeader.GetExchangeID(), session, !payloadHeader.IsInitiator(),
nullptr, true /* IsStandaloneExchange */);

if (ec == nullptr)
{
// Using same error message for all errors to reduce code size.
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(CHIP_ERROR_NO_MEMORY));
return;
}

ChipLogDetail(ExchangeManager, "Generating StandaloneAck via exchange: " ChipLogFormatExchange, ChipLogValueExchange(ec));

// Make sure the exchange stays alive through the code below even if we
// close it before calling HandleMessage.
ExchangeHandle ref(*ec);

// Ignore encryption-required mismatches for emphemeral exchanges,
// because those never have delegates anyway.
if (matchingUMH != nullptr && ec->IsEncryptionRequired() != packetHeader.IsEncrypted())
{
// We want to still to do MRP processing for this message, but we do
// not want to deliver it to the application. Just close the
// exchange (which will notify the delegate, null it out, etc), then
// go ahead and call HandleMessage() on it to do the MRP
// processing.null out the delegate on the exchange, pretend to
// matchingUMH that exchange creation failed, so it cleans up the
// delegate, then tell the exchagne to handle the message.
ChipLogProgress(ExchangeManager, "OnMessageReceived encryption mismatch");
ec->Close();
}
// No need to verify packet encryption type, the StandaloneExchange can handle both secure and insecure messages.

CHIP_ERROR err = ec->HandleMessage(packetHeader.GetMessageCounter(), payloadHeader, msgFlags, std::move(msgBuf));
if (err != CHIP_NO_ERROR)
{
// Using same error message for all errors to reduce code size.
ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %s", ErrorStr(err));
}

// The exchange should be closed inside HandleMessage function. So don't bother close it here.
return;
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/messaging/ReliableMessageContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ class ReliableMessageContext
/// Determine whether this exchange is requesting Sleepy End Device active mode
bool IsRequestingActiveMode() const;

/// Determine whether this exchange is a StandaloneExchange for replying a StandaloneAck
bool IsStandaloneExchange() const;

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

/// When set, signifies that the exchange is requesting Sleepy End Device active mode.
kFlagActiveMode = (1u << 8),

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

BitFlags<Flags> mFlags; // Internal state flags
Expand Down Expand Up @@ -234,5 +240,10 @@ inline void ReliableMessageContext::SetRequestingActiveMode(bool activeMode)
mFlags.Set(Flags::kFlagActiveMode, activeMode);
}

inline bool ReliableMessageContext::IsStandaloneExchange() const
{
return mFlags.Has(Flags::kFlagStandaloneExchange);
}

} // namespace Messaging
} // namespace chip
61 changes: 61 additions & 0 deletions src/messaging/StandaloneExchangeDispatch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file
* This file defines Application Channel class. The object of this
* class can be used by CHIP data model cluster applications to send
* and receive messages. The messages are encrypted using session keys.
*/

#pragma once

#include <messaging/ExchangeMessageDispatch.h>
#include <protocols/secure_channel/Constants.h>

namespace chip {
namespace Messaging {

class StandaloneExchangeDispatch : public ExchangeMessageDispatch
{
public:
static ExchangeMessageDispatch & Instance()
{
static StandaloneExchangeDispatch instance;
return instance;
}

StandaloneExchangeDispatch() {}
~StandaloneExchangeDispatch() override {}

protected:
bool MessagePermitted(Protocols::Id protocol, uint8_t type) override
{
// Only permit StandaloneAck
return (protocol == Protocols::SecureChannel::Id &&
type == static_cast<uint8_t>(Protocols::SecureChannel::MsgType::StandaloneAck));
}

bool IsEncryptionRequired() const override
{
// This function should not be called at all
VerifyOrDie(false);
return false;
}
};

} // namespace Messaging
} // namespace chip

0 comments on commit 58917eb

Please sign in to comment.