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

StandaloneAck handling: Untangle code path for UMH and StandaloneAck #19443

Merged
merged 3 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
61 changes: 61 additions & 0 deletions src/messaging/EphemeralExchangeDispatch.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.
kghost marked this conversation as resolved.
Show resolved Hide resolved
*/

#pragma once

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

namespace chip {
namespace Messaging {

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

EphemeralExchangeDispatch() {}
~EphemeralExchangeDispatch() 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));
kghost marked this conversation as resolved.
Show resolved Hide resolved
}

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

} // namespace Messaging
} // namespace chip
23 changes: 21 additions & 2 deletions src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <lib/support/TypeTraits.h>
#include <lib/support/logging/CHIPLogging.h>
#include <messaging/ApplicationExchangeDispatch.h>
#include <messaging/EphemeralExchangeDispatch.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeMgr.h>
#include <protocols/Protocols.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 isEphemeralExchange) :
mDispatch(GetMessageDispatch(isEphemeralExchange, 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::kFlagEphemeralExchange, isEphemeralExchange);
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 (IsEphemeralExchange())
{
// The EphemeralExchange 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 isEphemeralExchange, ExchangeDelegate * delegate)
{
if (isEphemeralExchange)
return EphemeralExchangeDispatch::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 isEphemeralExchange = 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 isEphemeralExchange, ExchangeDelegate * delegate);
};

} // namespace Messaging
Expand Down
80 changes: 54 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;
kghost marked this conversation as resolved.
Show resolved Hide resolved
}

// If rcvd msg is from initiator then this exchange is created as not Initiator.
kghost marked this conversation as resolved.
Show resolved Hide resolved
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,63 @@ 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();
ReplyStandaloneAck(packetHeader, payloadHeader, session, msgFlags, std::move(msgBuf));
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;
}

ReplyStandaloneAck(packetHeader, payloadHeader, session, msgFlags, std::move(msgBuf));
return;
}

void ExchangeManager::ReplyStandaloneAck(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
kghost marked this conversation as resolved.
Show resolved Hide resolved
const SessionHandle & session, MessageFlags msgFlags, System::PacketBufferHandle && msgBuf)
{
// If we need to send a StandaloneAck, create a EphemeralExchange for the purpose to send the StandaloneAck
if (payloadHeader.NeedsAck())
kghost marked this conversation as resolved.
Show resolved Hide resolved
{
// 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 EphemeralExchange to generate a StandaloneAck
ExchangeContext * ec = mContextPool.CreateObject(this, payloadHeader.GetExchangeID(), session, !payloadHeader.IsInitiator(),
nullptr, true /* IsEphemeralExchange */);

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);
kghost marked this conversation as resolved.
Show resolved Hide resolved

// 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 EphemeralExchange 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
2 changes: 2 additions & 0 deletions src/messaging/ExchangeMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ class DLL_EXPORT ExchangeManager : public SessionMessageDelegate

void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, const SessionHandle & session,
DuplicateMessage isDuplicate, System::PacketBufferHandle && msgBuf) override;
void ReplyStandaloneAck(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, const SessionHandle & session,
MessageFlags msgFlags, System::PacketBufferHandle && msgBuf);
};

} // namespace Messaging
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 EphemeralExchange for replying a StandaloneAck
bool IsEphemeralExchange() 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
kFlagEphemeralExchange = (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::IsEphemeralExchange() const
{
return mFlags.Has(Flags::kFlagEphemeralExchange);
}

} // namespace Messaging
} // namespace chip