From 10677305a7ccab451a8b30ac2838dacd9cdd32e4 Mon Sep 17 00:00:00 2001 From: yunhanw-google Date: Tue, 2 Nov 2021 08:31:34 -0700 Subject: [PATCH] Refresh IM Invoke encoding with latest spec (#11169) --- src/app/BUILD.gn | 12 +- src/app/Command.cpp | 156 +------ src/app/Command.h | 31 +- src/app/CommandHandler.cpp | 175 ++++++-- src/app/CommandHandler.h | 29 +- src/app/CommandSender.cpp | 181 ++++++-- src/app/CommandSender.h | 27 +- src/app/InteractionModelEngine.h | 1 - src/app/MessageDef/CommandDataIB.cpp | 197 +++------ src/app/MessageDef/CommandDataIB.h | 54 +-- src/app/MessageDef/CommandList.cpp | 111 ----- src/app/MessageDef/CommandPathIB.cpp | 11 +- src/app/MessageDef/CommandPathIB.h | 14 +- src/app/MessageDef/CommandStatusIB.cpp | 144 ++++++ src/app/MessageDef/CommandStatusIB.h | 115 +++++ src/app/MessageDef/InvokeCommand.cpp | 161 ------- src/app/MessageDef/InvokeRequestMessage.cpp | 174 ++++++++ src/app/MessageDef/InvokeRequestMessage.h | 136 ++++++ src/app/MessageDef/InvokeRequests.cpp | 89 ++++ .../{CommandList.h => InvokeRequests.h} | 34 +- src/app/MessageDef/InvokeResponseIB.cpp | 151 +++++++ .../{InvokeCommand.h => InvokeResponseIB.h} | 86 ++-- src/app/MessageDef/InvokeResponseMessage.cpp | 138 ++++++ src/app/MessageDef/InvokeResponseMessage.h | 114 +++++ src/app/MessageDef/InvokeResponses.cpp | 89 ++++ src/app/MessageDef/InvokeResponses.h | 82 ++++ .../operational-credentials-server.cpp | 3 +- src/app/tests/TestCommandInteraction.cpp | 202 ++++++--- src/app/tests/TestMessageDef.cpp | 410 ++++++++++++++---- .../tests/integration/chip_im_initiator.cpp | 1 - src/lib/core/CHIPError.cpp | 12 + src/lib/core/CHIPError.h | 36 ++ 32 files changed, 2240 insertions(+), 936 deletions(-) delete mode 100644 src/app/MessageDef/CommandList.cpp create mode 100644 src/app/MessageDef/CommandStatusIB.cpp create mode 100644 src/app/MessageDef/CommandStatusIB.h delete mode 100644 src/app/MessageDef/InvokeCommand.cpp create mode 100644 src/app/MessageDef/InvokeRequestMessage.cpp create mode 100644 src/app/MessageDef/InvokeRequestMessage.h create mode 100644 src/app/MessageDef/InvokeRequests.cpp rename src/app/MessageDef/{CommandList.h => InvokeRequests.h} (77%) create mode 100644 src/app/MessageDef/InvokeResponseIB.cpp rename src/app/MessageDef/{InvokeCommand.h => InvokeResponseIB.h} (55%) create mode 100644 src/app/MessageDef/InvokeResponseMessage.cpp create mode 100644 src/app/MessageDef/InvokeResponseMessage.h create mode 100644 src/app/MessageDef/InvokeResponses.cpp create mode 100644 src/app/MessageDef/InvokeResponses.h diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 066723102194f9..5817f598e9e6f8 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -60,11 +60,8 @@ static_library("app") { "MessageDef/Builder.cpp", "MessageDef/Builder.h", "MessageDef/CommandDataIB.cpp", - "MessageDef/CommandDataIB.h", - "MessageDef/CommandList.cpp", - "MessageDef/CommandList.h", "MessageDef/CommandPathIB.cpp", - "MessageDef/CommandPathIB.h", + "MessageDef/CommandStatusIB.cpp", "MessageDef/EventDataElement.cpp", "MessageDef/EventDataElement.h", "MessageDef/EventFilterIB.cpp", @@ -75,8 +72,11 @@ static_library("app") { "MessageDef/EventPathIB.h", "MessageDef/EventPaths.cpp", "MessageDef/EventPaths.h", - "MessageDef/InvokeCommand.cpp", - "MessageDef/InvokeCommand.h", + "MessageDef/InvokeRequestMessage.cpp", + "MessageDef/InvokeRequests.cpp", + "MessageDef/InvokeResponseIB.cpp", + "MessageDef/InvokeResponseMessage.cpp", + "MessageDef/InvokeResponses.cpp", "MessageDef/ListBuilder.cpp", "MessageDef/ListParser.cpp", "MessageDef/MessageDefHelper.cpp", diff --git a/src/app/Command.cpp b/src/app/Command.cpp index b2bdcb305090eb..22f7198477c68e 100644 --- a/src/app/Command.cpp +++ b/src/app/Command.cpp @@ -23,10 +23,6 @@ */ #include "Command.h" -#include "CommandHandler.h" -#include "CommandSender.h" -#include "InteractionModelEngine.h" - #include #include @@ -35,165 +31,21 @@ namespace app { Command::Command() {} -CHIP_ERROR Command::AllocateBuffer() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - CommandList::Builder commandListBuilder; - - if (!mBufferAllocated) - { - mCommandMessageWriter.Reset(); - - System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); - VerifyOrExit(!commandPacket.IsNull(), err = CHIP_ERROR_NO_MEMORY); - - mCommandMessageWriter.Init(std::move(commandPacket)); - err = mInvokeCommandBuilder.Init(&mCommandMessageWriter); - SuccessOrExit(err); - - commandListBuilder = mInvokeCommandBuilder.CreateCommandListBuilder(); - err = commandListBuilder.GetError(); - SuccessOrExit(err); - - mCommandIndex = 0; - - mBufferAllocated = true; - } - -exit: - return err; -} - -CHIP_ERROR Command::ProcessCommandMessage(System::PacketBufferHandle && payload, CommandRoleId aCommandRoleId) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::System::PacketBufferTLVReader reader; - chip::TLV::TLVReader commandListReader; - InvokeCommand::Parser invokeCommandParser; - CommandList::Parser commandListParser; - - reader.Init(std::move(payload)); - err = reader.Next(); - SuccessOrExit(err); - - err = invokeCommandParser.Init(reader); - SuccessOrExit(err); - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = invokeCommandParser.CheckSchemaValidity(); - SuccessOrExit(err); -#endif - err = invokeCommandParser.GetCommandList(&commandListParser); - SuccessOrExit(err); - - commandListParser.GetReader(&commandListReader); - - while (CHIP_NO_ERROR == (err = commandListReader.Next())) - { - VerifyOrExit(chip::TLV::AnonymousTag == commandListReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - VerifyOrExit(chip::TLV::kTLVType_Structure == commandListReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - CommandDataIB::Parser commandElement; - - err = commandElement.Init(commandListReader); - SuccessOrExit(err); - - err = ProcessCommandDataIB(commandElement); - SuccessOrExit(err); - } - - // if we have exhausted this container - if (CHIP_END_OF_TLV == err) - { - err = CHIP_NO_ERROR; - } - -exit: - return err; -} - -CHIP_ERROR Command::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - CommandDataIB::Builder commandDataIB; - - err = AllocateBuffer(); - SuccessOrExit(err); - - // - // We must not be in the middle of preparing a command, or having prepared or sent one. - // - VerifyOrExit(mState == CommandState::Idle, err = CHIP_ERROR_INCORRECT_STATE); - - commandDataIB = mInvokeCommandBuilder.GetCommandListBuilder().CreateCommandDataIBBuilder(); - err = commandDataIB.GetError(); - SuccessOrExit(err); - - err = ConstructCommandPath(aCommandPathParams, commandDataIB); - SuccessOrExit(err); - - if (aStartDataStruct) - { - err = commandDataIB.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::kCsTag_Data), TLV::kTLVType_Structure, - mDataElementContainerType); - } - - MoveToState(CommandState::AddingCommand); - -exit: - return err; -} - -TLV::TLVWriter * Command::GetCommandDataIBTLVWriter() -{ - if (mState != CommandState::AddingCommand) - { - return nullptr; - } - else - { - return mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder().GetWriter(); - } -} - CHIP_ERROR Command::Finalize(System::PacketBufferHandle & commandPacket) { VerifyOrReturnError(mState == CommandState::AddedCommand, CHIP_ERROR_INCORRECT_STATE); return mCommandMessageWriter.Finalize(&commandPacket); } -CHIP_ERROR Command::FinishCommand(bool aEndDataStruct) +CHIP_ERROR Command::ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandPathIB::Builder & aCommandPath) { - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrReturnError(mState == CommandState::AddingCommand, err = CHIP_ERROR_INCORRECT_STATE); - - CommandDataIB::Builder commandDataIB = mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder(); - if (aEndDataStruct) - { - ReturnErrorOnFailure(commandDataIB.GetWriter()->EndContainer(mDataElementContainerType)); - } - - ReturnErrorOnFailure(commandDataIB.EndOfCommandDataIB().GetError()); - ReturnErrorOnFailure(mInvokeCommandBuilder.GetCommandListBuilder().EndOfCommandList().GetError()); - ReturnErrorOnFailure(mInvokeCommandBuilder.EndOfInvokeCommand().GetError()); - - MoveToState(CommandState::AddedCommand); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR Command::ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandDataIB::Builder aCommandDataIB) -{ - CommandPathIB::Builder commandPath = aCommandDataIB.CreateCommandPathBuilder(); if (aCommandPathParams.mFlags.Has(CommandPathFlags::kEndpointIdValid)) { - commandPath.EndpointId(aCommandPathParams.mEndpointId); + aCommandPath.EndpointId(aCommandPathParams.mEndpointId); } - commandPath.ClusterId(aCommandPathParams.mClusterId).CommandId(aCommandPathParams.mCommandId).EndOfCommandPath(); - - return commandPath.GetError(); + aCommandPath.ClusterId(aCommandPathParams.mClusterId).CommandId(aCommandPathParams.mCommandId).EndOfCommandPathIB(); + return aCommandPath.GetError(); } void Command::Abort() diff --git a/src/app/Command.h b/src/app/Command.h index f396ad778c789d..5e8cb64b62f0c8 100644 --- a/src/app/Command.h +++ b/src/app/Command.h @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -47,12 +45,6 @@ namespace app { class Command { public: - enum class CommandRoleId - { - SenderId = 0, - HandlerId = 1, - }; - enum class CommandState { Idle, ///< Default state that the object starts out in, where no work has commenced @@ -70,12 +62,6 @@ class Command */ virtual ~Command() { Abort(); } - /* - * A set of methods to construct command request or response payloads - */ - CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); - TLV::TLVWriter * GetCommandDataIBTLVWriter(); - CHIP_ERROR FinishCommand(bool aEndDataStruct = true); CHIP_ERROR Finalize(System::PacketBufferHandle & commandPacket); virtual CHIP_ERROR AddStatus(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus) @@ -102,19 +88,9 @@ class Command */ Messaging::ExchangeContext * GetExchangeContext() const { return mpExchangeCtx; } - virtual CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) = 0; - protected: Command(); - /* - * Allocates a packet buffer used for encoding an invoke request/response payload. - * - * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime - * of this object. - */ - CHIP_ERROR AllocateBuffer(); - /* * The actual closure of the exchange happens automatically in the exchange layer. * This function just sets the internally tracked exchange pointer to null to align @@ -123,15 +99,14 @@ class Command void Close(); void MoveToState(const CommandState aTargetState); - CHIP_ERROR ProcessCommandMessage(System::PacketBufferHandle && payload, CommandRoleId aCommandRoleId); - CHIP_ERROR ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandDataIB::Builder aCommandDataIB); + CHIP_ERROR ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandPathIB::Builder & aCommandPath); const char * GetStateStr() const; - InvokeCommand::Builder mInvokeCommandBuilder; Messaging::ExchangeContext * mpExchangeCtx = nullptr; uint8_t mCommandIndex = 0; CommandState mState = CommandState::Idle; chip::System::PacketBufferTLVWriter mCommandMessageWriter; + bool mBufferAllocated = false; private: /* @@ -143,8 +118,6 @@ class Command void Abort(); friend class TestCommandInteraction; - TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; - bool mBufferAllocated = false; }; } // namespace app } // namespace chip diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index 44612eeed3df81..eaf03d3a9998c8 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -34,7 +34,32 @@ namespace chip { namespace app { -CommandHandler::CommandHandler(Callback * apCallback) : mpCallback(apCallback) {} +CommandHandler::CommandHandler(Callback * apCallback) : mpCallback(apCallback), mSuppressResponse(false) {} + +CHIP_ERROR CommandHandler::AllocateBuffer() +{ + if (!mBufferAllocated) + { + mCommandMessageWriter.Reset(); + + System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); + VerifyOrReturnError(!commandPacket.IsNull(), CHIP_ERROR_NO_MEMORY); + + mCommandMessageWriter.Init(std::move(commandPacket)); + ReturnErrorOnFailure(mInvokeResponseBuilder.Init(&mCommandMessageWriter)); + + mInvokeResponseBuilder.SuppressResponse(mSuppressResponse); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetError()); + + mInvokeResponseBuilder.CreateInvokeResponses(); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetError()); + + mCommandIndex = 0; + mBufferAllocated = true; + } + + return CHIP_NO_ERROR; +} CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader, System::PacketBufferHandle && payload) @@ -49,7 +74,7 @@ CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * e mpExchangeCtx = ec; - err = ProcessCommandMessage(std::move(payload), CommandRoleId::HandlerId); + err = ProcessInvokeRequest(std::move(payload)); SuccessOrExit(err); err = SendCommandResponse(); @@ -60,8 +85,43 @@ CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * e return err; } +CHIP_ERROR CommandHandler::ProcessInvokeRequest(System::PacketBufferHandle && payload) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferTLVReader reader; + TLV::TLVReader invokeRequestsReader; + InvokeRequestMessage::Parser invokeRequestMessage; + InvokeRequests::Parser invokeRequests; + reader.Init(std::move(payload)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(invokeRequestMessage.Init(reader)); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + ReturnErrorOnFailure(invokeRequestMessage.CheckSchemaValidity()); +#endif + ReturnErrorOnFailure(invokeRequestMessage.GetSuppressResponse(&mSuppressResponse)); + ReturnErrorOnFailure(invokeRequestMessage.GetTimedRequest(&mTimedRequest)); + ReturnErrorOnFailure(invokeRequestMessage.GetInvokeRequests(&invokeRequests)); + + invokeRequests.GetReader(&invokeRequestsReader); + while (CHIP_NO_ERROR == (err = invokeRequestsReader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == invokeRequestsReader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + CommandDataIB::Parser commandData; + ReturnErrorOnFailure(commandData.Init(invokeRequestsReader)); + ReturnErrorOnFailure(ProcessCommandDataIB(commandData)); + } + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + err = CHIP_NO_ERROR; + } + return err; +} + void CommandHandler::Close() { + mSuppressResponse = false; MoveToState(CommandState::AwaitingDestruction); Command::Close(); @@ -94,12 +154,12 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand { CHIP_ERROR err = CHIP_NO_ERROR; CommandPathIB::Parser commandPath; - chip::TLV::TLVReader commandDataReader; - chip::ClusterId clusterId; - chip::CommandId commandId; - chip::EndpointId endpointId; + TLV::TLVReader commandDataReader; + ClusterId clusterId; + CommandId commandId; + EndpointId endpointId; - err = aCommandElement.GetCommandPath(&commandPath); + err = aCommandElement.GetPath(&commandPath); SuccessOrExit(err); err = commandPath.GetClusterId(&clusterId); @@ -110,10 +170,8 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand err = commandPath.GetEndpointId(&endpointId); SuccessOrExit(err); - VerifyOrExit(ServerClusterCommandExists(ConcreteCommandPath(endpointId, clusterId, commandId)), err = CHIP_ERROR_INVALID_PROFILE_ID); - err = aCommandElement.GetData(&commandDataReader); if (CHIP_END_OF_TLV == err) { @@ -134,7 +192,7 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand exit: if (err != CHIP_NO_ERROR) { - chip::app::ConcreteCommandPath path(endpointId, clusterId, commandId); + ConcreteCommandPath path(endpointId, clusterId, commandId); // The Path is the path in the request if there are any error occurred before we dispatch the command to clusters. // Currently, it could be failed to decode Path or failed to find cluster / command on desired endpoint. @@ -159,19 +217,16 @@ CHIP_ERROR CommandHandler::AddStatusInternal(const ConcreteCommandPath & aComman const Protocols::InteractionModel::Status aStatus, const Optional & aClusterStatus) { - CHIP_ERROR err = CHIP_NO_ERROR; StatusIB::Builder statusIBBuilder; StatusIB statusIB; - chip::app::CommandPathParams commandPathParams = { aCommandPath.mEndpointId, - 0, // GroupId - aCommandPath.mClusterId, aCommandPath.mCommandId, - chip::app::CommandPathFlags::kEndpointIdValid }; - - err = PrepareCommand(commandPathParams, false /* aStartDataStruct */); - SuccessOrExit(err); + CommandPathParams commandPathParams = { aCommandPath.mEndpointId, + 0, // GroupId + aCommandPath.mClusterId, aCommandPath.mCommandId, + chip::app::CommandPathFlags::kEndpointIdValid }; - statusIBBuilder = mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder().CreateStatusIBBuilder(); + ReturnLogErrorOnFailure(PrepareStatus(commandPathParams)); + statusIBBuilder = mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().GetStatus().CreateErrorStatus(); // // TODO: Most of the callers are incorrectly passing SecureChannel as the protocol ID, when in fact, the status code provided @@ -181,13 +236,8 @@ CHIP_ERROR CommandHandler::AddStatusInternal(const ConcreteCommandPath & aComman statusIB.mStatus = aStatus; statusIB.mClusterStatus = aClusterStatus; statusIBBuilder.EncodeStatusIB(statusIB); - err = statusIBBuilder.GetError(); - SuccessOrExit(err); - - err = FinishCommand(false /* aEndDataStruct */); - -exit: - return err; + ReturnLogErrorOnFailure(statusIBBuilder.GetError()); + return FinishStatus(); } CHIP_ERROR CommandHandler::AddStatus(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus) @@ -216,5 +266,78 @@ CHIP_ERROR CommandHandler::PrepareResponse(const ConcreteCommandPath & aRequestC return PrepareCommand(params, false /* aStartDataStruct */); } +CHIP_ERROR CommandHandler::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) +{ + ReturnErrorOnFailure(AllocateBuffer()); + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrReturnError(mState == CommandState::Idle, CHIP_ERROR_INCORRECT_STATE); + CommandDataIB::Builder commandData = mInvokeResponseBuilder.GetInvokeResponses().CreateInvokeResponse().CreateCommand(); + ReturnErrorOnFailure(commandData.GetError()); + ReturnErrorOnFailure(ConstructCommandPath(aCommandPathParams, commandData.CreatePath())); + if (aStartDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->StartContainer(TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), + TLV::kTLVType_Structure, mDataElementContainerType)); + } + MoveToState(CommandState::AddingCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::FinishCommand(bool aStartDataStruct) +{ + VerifyOrReturnError(mState == CommandState::AddingCommand, CHIP_ERROR_INCORRECT_STATE); + CommandDataIB::Builder commandData = mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().GetCommand(); + if (aStartDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->EndContainer(mDataElementContainerType)); + } + ReturnErrorOnFailure(commandData.EndOfCommandDataIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().EndOfInvokeResponseIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetInvokeResponses().EndOfInvokeResponses().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.EndOfInvokeResponseMessage().GetError()); + MoveToState(CommandState::AddedCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::PrepareStatus(const CommandPathParams & aCommandPathParams) +{ + ReturnErrorOnFailure(AllocateBuffer()); + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrReturnError(mState == CommandState::Idle, CHIP_ERROR_INCORRECT_STATE); + CommandStatusIB::Builder commandStatus = mInvokeResponseBuilder.GetInvokeResponses().CreateInvokeResponse().CreateStatus(); + ReturnErrorOnFailure(commandStatus.GetError()); + ReturnErrorOnFailure(ConstructCommandPath(aCommandPathParams, commandStatus.CreatePath())); + MoveToState(CommandState::AddingCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::FinishStatus() +{ + VerifyOrReturnError(mState == CommandState::AddingCommand, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure( + mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().GetStatus().EndOfCommandStatusIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().EndOfInvokeResponseIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.GetInvokeResponses().EndOfInvokeResponses().GetError()); + ReturnErrorOnFailure(mInvokeResponseBuilder.EndOfInvokeResponseMessage().GetError()); + MoveToState(CommandState::AddedCommand); + return CHIP_NO_ERROR; +} + +TLV::TLVWriter * CommandHandler::GetCommandDataIBTLVWriter() +{ + if (mState != CommandState::AddingCommand) + { + return nullptr; + } + else + { + return mInvokeResponseBuilder.GetInvokeResponses().GetInvokeResponse().GetCommand().GetWriter(); + } +} + } // namespace app } // namespace chip diff --git a/src/app/CommandHandler.h b/src/app/CommandHandler.h index 38837957397be0..3bcd67df051f96 100644 --- a/src/app/CommandHandler.h +++ b/src/app/CommandHandler.h @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -39,6 +38,9 @@ #include #include +#include +#include + namespace chip { namespace app { @@ -78,6 +80,13 @@ class CommandHandler : public Command CHIP_ERROR AddClusterSpecificFailure(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus) override; + CHIP_ERROR ProcessInvokeRequest(System::PacketBufferHandle && payload); + CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); + CHIP_ERROR FinishCommand(bool aStartDataStruct = true); + CHIP_ERROR PrepareStatus(const CommandPathParams & aCommandPathParams); + CHIP_ERROR FinishStatus(); + TLV::TLVWriter * GetCommandDataIBTLVWriter(); + /** * API for adding a data response. The template parameter T is generally * expected to be a ClusterName::Commands::CommandName::Type struct, but any @@ -94,12 +103,21 @@ class CommandHandler : public Command ReturnErrorOnFailure(PrepareResponse(aRequestCommandPath, CommandData::GetCommandId())); TLV::TLVWriter * writer = GetCommandDataIBTLVWriter(); VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::kCsTag_Data), aData)); + ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), aData)); return FinishCommand(/* aEndDataStruct = */ false); } private: + friend class TestCommandInteraction; + /* + * Allocates a packet buffer used for encoding an invoke response payload. + * + * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime + * of this object. + */ + CHIP_ERROR AllocateBuffer(); + // // Called internally to signal the completion of all work on this object, gracefully close the // exchange (by calling into the base class) and finally, signal to a registerd callback that it's @@ -107,14 +125,17 @@ class CommandHandler : public Command // void Close(); - friend class TestCommandInteraction; + CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement); CHIP_ERROR SendCommandResponse(); - CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) override; CHIP_ERROR PrepareResponse(const ConcreteCommandPath & aRequestCommandPath, CommandId aResponseCommand); CHIP_ERROR AddStatusInternal(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus, const Optional & aClusterStatus); Callback * mpCallback = nullptr; + InvokeResponseMessage::Builder mInvokeResponseBuilder; + TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; + bool mSuppressResponse = false; + bool mTimedRequest = false; }; } // namespace app } // namespace chip diff --git a/src/app/CommandSender.cpp b/src/app/CommandSender.cpp index c400caeac7a38c..d2cb41f4847dae 100644 --- a/src/app/CommandSender.cpp +++ b/src/app/CommandSender.cpp @@ -33,9 +33,34 @@ namespace chip { namespace app { CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr) : - mpCallback(apCallback), mpExchangeMgr(apExchangeMgr) + mpCallback(apCallback), mpExchangeMgr(apExchangeMgr), mSuppressResponse(false), mTimedRequest(false) {} +CHIP_ERROR CommandSender::AllocateBuffer() +{ + if (!mBufferAllocated) + { + mCommandMessageWriter.Reset(); + + System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); + VerifyOrReturnError(!commandPacket.IsNull(), CHIP_ERROR_NO_MEMORY); + + mCommandMessageWriter.Init(std::move(commandPacket)); + ReturnErrorOnFailure(mInvokeRequestBuilder.Init(&mCommandMessageWriter)); + + mInvokeRequestBuilder.SuppressResponse(mSuppressResponse).TimedRequest(mTimedRequest); + ReturnErrorOnFailure(mInvokeRequestBuilder.GetError()); + + mInvokeRequestBuilder.CreateInvokeRequests(); + ReturnErrorOnFailure(mInvokeRequestBuilder.GetError()); + + mCommandIndex = 0; + mBufferAllocated = true; + } + + return CHIP_NO_ERROR; +} + CHIP_ERROR CommandSender::SendCommandRequest(SessionHandle session, System::Clock::Timeout timeout) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -71,7 +96,7 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha VerifyOrExit(aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::InvokeCommandResponse), err = CHIP_ERROR_INVALID_MESSAGE_TYPE); - SuccessOrExit(err = ProcessCommandMessage(std::move(aPayload), CommandRoleId::SenderId)); + err = ProcessInvokeResponse(std::move(aPayload)); exit: if (mpCallback != nullptr) @@ -89,6 +114,43 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha return err; } +CHIP_ERROR CommandSender::ProcessInvokeResponse(System::PacketBufferHandle && payload) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferTLVReader reader; + TLV::TLVReader invokeResponsesReader; + InvokeResponseMessage::Parser invokeResponseMessage; + InvokeResponses::Parser invokeResponses; + bool suppressResponse = false; + + reader.Init(std::move(payload)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(invokeResponseMessage.Init(reader)); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + ReturnErrorOnFailure(invokeResponseMessage.CheckSchemaValidity()); +#endif + + ReturnErrorOnFailure(invokeResponseMessage.GetSuppressResponse(&suppressResponse)); + ReturnErrorOnFailure(invokeResponseMessage.GetInvokeResponses(&invokeResponses)); + invokeResponses.GetReader(&invokeResponsesReader); + + while (CHIP_NO_ERROR == (err = invokeResponsesReader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == invokeResponsesReader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + InvokeResponseIB::Parser invokeResponse; + ReturnErrorOnFailure(invokeResponse.Init(invokeResponsesReader)); + ReturnErrorOnFailure(ProcessInvokeResponseIB(invokeResponse)); + } + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + err = CHIP_NO_ERROR; + } + return err; +} + void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) { ChipLogProgress(DataManagement, "Time out! failed to receive invoke command response from Exchange: " ChipLogFormatExchange, @@ -106,6 +168,8 @@ void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeCon void CommandSender::Close() { + mSuppressResponse = false; + mTimedRequest = false; MoveToState(CommandState::AwaitingDestruction); Command::Close(); @@ -116,45 +180,45 @@ void CommandSender::Close() } } -CHIP_ERROR CommandSender::ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) +CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aInvokeResponse) { CHIP_ERROR err = CHIP_NO_ERROR; - chip::ClusterId clusterId; - chip::CommandId commandId; - chip::EndpointId endpointId; + ClusterId clusterId; + CommandId commandId; + EndpointId endpointId; // Default to success when an invoke response is received. StatusIB statusIB; - { - CommandPathIB::Parser commandPath; - - err = aCommandElement.GetCommandPath(&commandPath); - SuccessOrExit(err); - - err = commandPath.GetClusterId(&clusterId); - SuccessOrExit(err); - - err = commandPath.GetCommandId(&commandId); - SuccessOrExit(err); - - err = commandPath.GetEndpointId(&endpointId); - SuccessOrExit(err); - } - { bool hasDataResponse = false; - chip::TLV::TLVReader commandDataReader; + TLV::TLVReader commandDataReader; - StatusIB::Parser statusIBParser; - err = aCommandElement.GetStatusIB(&statusIBParser); + CommandStatusIB::Parser commandStatus; + err = aInvokeResponse.GetStatus(&commandStatus); if (CHIP_NO_ERROR == err) { - err = statusIBParser.DecodeStatusIB(statusIB); + CommandPathIB::Parser commandPath; + commandStatus.GetPath(&commandPath); + ReturnErrorOnFailure(commandPath.GetClusterId(&clusterId)); + ReturnErrorOnFailure(commandPath.GetCommandId(&commandId)); + ReturnErrorOnFailure(commandPath.GetEndpointId(&endpointId)); + + StatusIB::Parser status; + commandStatus.GetErrorStatus(&status); + ReturnErrorOnFailure(status.DecodeStatusIB(statusIB)); } else if (CHIP_END_OF_TLV == err) { + CommandDataIB::Parser commandData; + CommandPathIB::Parser commandPath; + ReturnErrorOnFailure(aInvokeResponse.GetCommand(&commandData)); + ReturnErrorOnFailure(commandData.GetPath(&commandPath)); + ReturnErrorOnFailure(commandPath.GetEndpointId(&endpointId)); + ReturnErrorOnFailure(commandPath.GetClusterId(&clusterId)); + ReturnErrorOnFailure(commandPath.GetCommandId(&commandId)); + commandData.GetData(&commandDataReader); + err = CHIP_NO_ERROR; hasDataResponse = true; - err = aCommandElement.GetData(&commandDataReader); } if (err != CHIP_NO_ERROR) @@ -179,7 +243,7 @@ CHIP_ERROR CommandSender::ProcessCommandDataIB(CommandDataIB::Parser & aCommandE to_underlying(statusIB.mStatus)); } } - SuccessOrExit(err); + ReturnErrorOnFailure(err); if (mpCallback != nullptr) { @@ -194,9 +258,66 @@ CHIP_ERROR CommandSender::ProcessCommandDataIB(CommandDataIB::Parser & aCommandE } } } + return CHIP_NO_ERROR; +} -exit: - return err; +CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) +{ + CommandDataIB::Builder commandData; + ReturnLogErrorOnFailure(AllocateBuffer()); + + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrReturnError(mState == CommandState::Idle, CHIP_ERROR_INCORRECT_STATE); + + commandData = mInvokeRequestBuilder.GetInvokeRequests().CreateCommandData(); + ReturnLogErrorOnFailure(commandData.GetError()); + + ReturnLogErrorOnFailure(ConstructCommandPath(aCommandPathParams, commandData.CreatePath())); + + if (aStartDataStruct) + { + ReturnLogErrorOnFailure(commandData.GetWriter()->StartContainer(TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), + TLV::kTLVType_Structure, mDataElementContainerType)); + } + + MoveToState(CommandState::AddingCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandSender::FinishCommand(bool aEndDataStruct) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrReturnError(mState == CommandState::AddingCommand, err = CHIP_ERROR_INCORRECT_STATE); + + CommandDataIB::Builder commandData = mInvokeRequestBuilder.GetInvokeRequests().GetCommandData(); + + if (aEndDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->EndContainer(mDataElementContainerType)); + } + + ReturnErrorOnFailure(commandData.EndOfCommandDataIB().GetError()); + ReturnErrorOnFailure(mInvokeRequestBuilder.GetInvokeRequests().EndOfInvokeRequests().GetError()); + ReturnErrorOnFailure(mInvokeRequestBuilder.EndOfInvokeRequestMessage().GetError()); + + MoveToState(CommandState::AddedCommand); + + return CHIP_NO_ERROR; +} + +TLV::TLVWriter * CommandSender::GetCommandDataIBTLVWriter() +{ + if (mState != CommandState::AddingCommand) + { + return nullptr; + } + else + { + return mInvokeRequestBuilder.GetInvokeRequests().GetCommandData().GetWriter(); + } } } // namespace app diff --git a/src/app/CommandSender.h b/src/app/CommandSender.h index 656f0a4e64333d..04ee3f9092b620 100644 --- a/src/app/CommandSender.h +++ b/src/app/CommandSender.h @@ -39,8 +39,8 @@ #include #include -#include -#include +#include +#include #define COMMON_STATUS_SUCCESS 0 @@ -117,7 +117,9 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate * The callback passed in has to outlive this CommandSender object. */ CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr); - + CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); + CHIP_ERROR FinishCommand(bool aEndDataStruct = true); + TLV::TLVWriter * GetCommandDataIBTLVWriter(); /** * API for adding a data request. The template parameter T is generally * expected to be a ClusterName::Commands::CommandName::Type struct, but any @@ -133,7 +135,7 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate ReturnErrorOnFailure(PrepareCommand(aCommandPath, /* aStartDataStruct = */ false)); TLV::TLVWriter * writer = GetCommandDataIBTLVWriter(); VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::kCsTag_Data), aData)); + ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), aData)); return FinishCommand(/* aEndDataStruct = */ false); } @@ -156,6 +158,16 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate CHIP_ERROR SendCommandRequest(SessionHandle session, System::Clock::Timeout timeout = kImMessageTimeout); private: + friend class TestCommandInteraction; + + /* + * Allocates a packet buffer used for encoding an invoke request payload. + * + * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime + * of this object. + */ + CHIP_ERROR AllocateBuffer(); + // ExchangeDelegate interface implementation. Private so people won't // accidentally call it on us when we're not being treated as an actual // ExchangeDelegate. @@ -170,10 +182,15 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate // void Close(); - CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) override; + CHIP_ERROR ProcessInvokeResponse(System::PacketBufferHandle && payload); + CHIP_ERROR ProcessInvokeResponseIB(InvokeResponseIB::Parser & aInvokeResponse); Callback * mpCallback = nullptr; Messaging::ExchangeManager * mpExchangeMgr = nullptr; + InvokeRequestMessage::Builder mInvokeRequestBuilder; + TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; + bool mSuppressResponse = false; + bool mTimedRequest = false; }; } // namespace app diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 517d83b66f8dba..fc8cedec5a41e0 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -39,7 +39,6 @@ #include #include -#include #include #include #include diff --git a/src/app/MessageDef/CommandDataIB.cpp b/src/app/MessageDef/CommandDataIB.cpp index c590fdc463bfdc..9bc01a873185ee 100644 --- a/src/app/MessageDef/CommandDataIB.cpp +++ b/src/app/MessageDef/CommandDataIB.cpp @@ -15,11 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines CommandDataIB parser and builder in CHIP interaction model - * - */ #include "CommandDataIB.h" @@ -31,13 +26,10 @@ #include -using namespace chip; -using namespace chip::TLV; - namespace chip { namespace app { CHIP_ERROR -CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) const +CommandDataIB::Parser::ParseData(TLV::TLVReader & aReader, int aDepth) const { CHIP_ERROR err = CHIP_NO_ERROR; @@ -47,14 +39,14 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con } else { - if (chip::TLV::IsContextTag(aReader.GetTag())) + if (TLV::IsContextTag(aReader.GetTag())) { - PRETTY_PRINT("\t0x%" PRIx32 " = ", chip::TLV::TagNumFromTag(aReader.GetTag())); + PRETTY_PRINT("\t0x%" PRIx32 " = ", TLV::TagNumFromTag(aReader.GetTag())); } - else if (chip::TLV::IsProfileTag(aReader.GetTag())) + else if (TLV::IsProfileTag(aReader.GetTag())) { - PRETTY_PRINT("\t0x%" PRIx32 "::0x%" PRIx32 " = ", chip::TLV::ProfileIdFromTag(aReader.GetTag()), - chip::TLV::TagNumFromTag(aReader.GetTag())); + PRETTY_PRINT("\t0x%" PRIx32 "::0x%" PRIx32 " = ", TLV::ProfileIdFromTag(aReader.GetTag()), + TLV::TagNumFromTag(aReader.GetTag())); } else { @@ -64,16 +56,16 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con switch (aReader.GetType()) { - case chip::TLV::kTLVType_Structure: + case TLV::kTLVType_Structure: PRETTY_PRINT("\t{"); break; - case chip::TLV::kTLVType_Array: + case TLV::kTLVType_Array: PRETTY_PRINT_SAMELINE("["); PRETTY_PRINT("\t\t"); break; - case chip::TLV::kTLVType_SignedInteger: { + case TLV::kTLVType_SignedInteger: { int64_t value_s64; err = aReader.Get(value_s64); @@ -83,7 +75,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - case chip::TLV::kTLVType_UnsignedInteger: { + case TLV::kTLVType_UnsignedInteger: { uint64_t value_u64; err = aReader.Get(value_u64); @@ -93,7 +85,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - case chip::TLV::kTLVType_FloatingPointNumber: { + case TLV::kTLVType_FloatingPointNumber: { double value_fp; err = aReader.Get(value_fp); @@ -102,7 +94,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con PRETTY_PRINT_SAMELINE("%lf, ", value_fp); break; } - case chip::TLV::kTLVType_Boolean: { + case TLV::kTLVType_Boolean: { bool value_b; err = aReader.Get(value_b); @@ -112,7 +104,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - case chip::TLV::kTLVType_UTF8String: { + case TLV::kTLVType_UTF8String: { char value_s[256]; err = aReader.GetString(value_s, sizeof(value_s)); @@ -130,7 +122,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - case chip::TLV::kTLVType_ByteString: { + case TLV::kTLVType_ByteString: { uint8_t value_b[256]; uint32_t len, readerLen; @@ -168,7 +160,7 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - case chip::TLV::kTLVType_Null: + case TLV::kTLVType_Null: PRETTY_PRINT_SAMELINE("NULL"); break; @@ -177,10 +169,10 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con break; } - if (aReader.GetType() == chip::TLV::kTLVType_Structure || aReader.GetType() == chip::TLV::kTLVType_Array) + if (aReader.GetType() == TLV::kTLVType_Structure || aReader.GetType() == TLV::kTLVType_Array) { - const char terminating_char = (aReader.GetType() == chip::TLV::kTLVType_Structure) ? '}' : ']'; - chip::TLV::TLVType type; + const char terminating_char = (aReader.GetType() == TLV::kTLVType_Structure) ? '}' : ']'; + TLV::TLVType type; IgnoreUnusedVariable(terminating_char); @@ -210,10 +202,9 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const { - CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; - chip::TLV::TLVReader reader; - uint32_t tagNum = 0; + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; PRETTY_PRINT("CommandDataIB ="); PRETTY_PRINT("{"); @@ -223,54 +214,29 @@ CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const while (CHIP_NO_ERROR == (err = reader.Next())) { - VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG); - - tagNum = chip::TLV::TagNumFromTag(reader.GetTag()); + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); switch (tagNum) { - case kCsTag_CommandPath: + case to_underlying(Tag::kPath): // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandPath)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_CommandPath); - VerifyOrExit(chip::TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kPath))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kPath)); { CommandPathIB::Parser path; - err = path.Init(reader); - SuccessOrExit(err); - + ReturnErrorOnFailure(path.Init(reader)); PRETTY_PRINT_INCDEPTH(); - err = path.CheckSchemaValidity(); - SuccessOrExit(err); + ReturnErrorOnFailure(path.CheckSchemaValidity()); PRETTY_PRINT_DECDEPTH(); } break; - case kCsTag_Data: + case to_underlying(Tag::kData): // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_Data); - - err = ParseData(reader, 0); - SuccessOrExit(err); - break; - case kCsTag_StatusIB: - // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_StatusIB)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_StatusIB); - - { - StatusIB::Parser status; - err = status.Init(reader); - SuccessOrExit(err); - - PRETTY_PRINT_INCDEPTH(); - err = status.CheckSchemaValidity(); - SuccessOrExit(err); - PRETTY_PRINT_DECDEPTH(); - } - + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kData))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kData)); + ReturnErrorOnFailure(ParseData(reader, 0)); break; default: PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); @@ -281,109 +247,50 @@ CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const PRETTY_PRINT("},"); PRETTY_PRINT(""); - // if we have exhausted this container if (CHIP_END_OF_TLV == err) { - // check for at most field: - const uint16_t CheckDataField = 1 << kCsTag_Data; - const uint16_t CheckStatusIBField = 1 << kCsTag_StatusIB; + const int RequiredFields = 1 << to_underlying(Tag::kPath); - if ((TagPresenceMask & CheckDataField) == CheckDataField && (TagPresenceMask & CheckStatusIBField) == CheckStatusIBField) + if ((TagPresenceMask & RequiredFields) == RequiredFields) { - // kCsTag_Data and kCsTag_StatusIB both exist - err = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + err = CHIP_NO_ERROR; } else { - err = CHIP_NO_ERROR; + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE; } } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); -exit: - return err; + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; } #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR CommandDataIB::Parser::GetCommandPath(CommandPathIB::Parser * const apCommandPath) const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandPath), reader); - SuccessOrExit(err); - - VerifyOrExit(chip::TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = apCommandPath->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; -} - -CHIP_ERROR CommandDataIB::Parser::GetData(chip::TLV::TLVReader * const apReader) const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_Data), *apReader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; -} - -CHIP_ERROR CommandDataIB::Parser::GetStatusIB(StatusIB::Parser * const apStatusIB) const +CHIP_ERROR CommandDataIB::Parser::GetPath(CommandPathIB::Parser * const apPath) const { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_StatusIB), reader); - SuccessOrExit(err); - - err = apStatusIB->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kPath)), reader)); + ReturnErrorOnFailure(apPath->Init(reader)); + return CHIP_NO_ERROR; } -CommandPathIB::Builder & CommandDataIB::Builder::CreateCommandPathBuilder() +CHIP_ERROR CommandDataIB::Parser::GetData(TLV::TLVReader * const apReader) const { - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandPathBuilder.ResetError(mError)); - - mError = mCommandPathBuilder.Init(mpWriter, kCsTag_CommandPath); - -exit: - // on error, mAttributePathBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandPathBuilder; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kData)), *apReader)); + return CHIP_NO_ERROR; } -StatusIB::Builder & CommandDataIB::Builder::CreateStatusIBBuilder() +CommandPathIB::Builder & CommandDataIB::Builder::CreatePath() { - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mStatusIBBuilder.ResetError(mError)); - - mError = mStatusIBBuilder.Init(mpWriter, kCsTag_StatusIB); - -exit: - // on error, mStatusIBBuilder would be un-/partial initialized and cannot be used to write anything - return mStatusIBBuilder; + mError = mPath.Init(mpWriter, to_underlying(Tag::kPath)); + return mPath; } CommandDataIB::Builder & CommandDataIB::Builder::EndOfCommandDataIB() { EndOfContainer(); - return *this; } -}; // namespace app -}; // namespace chip +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/CommandDataIB.h b/src/app/MessageDef/CommandDataIB.h index fa6476e504dd4f..3b1eca9f91e623 100644 --- a/src/app/MessageDef/CommandDataIB.h +++ b/src/app/MessageDef/CommandDataIB.h @@ -15,19 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines CommandDataIB parser and builder in CHIP interaction model - * - */ #pragma once -#include "Builder.h" #include "CommandPathIB.h" - -#include "Parser.h" #include "StatusIB.h" +#include "StructBuilder.h" +#include "StructParser.h" #include #include @@ -39,11 +33,10 @@ namespace chip { namespace app { namespace CommandDataIB { -enum +enum class Tag : uint8_t { - kCsTag_CommandPath = 0, - kCsTag_Data = 1, - kCsTag_StatusIB = 2, + kPath = 0, + kData = 1, }; class Parser : public StructParser @@ -69,13 +62,13 @@ class Parser : public StructParser /** * @brief Get a TLVReader for the CommandPathIB. Next() must be called before accessing them. * - * @param [in] apCommandPath A pointer to apCommandPath + * @param [in] apPath A pointer to apCommandPath * * @return #CHIP_NO_ERROR on success * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetCommandPath(CommandPathIB::Parser * const apCommandPath) const; + CHIP_ERROR GetPath(CommandPathIB::Parser * const apPath) const; /** * @brief Get a TLVReader for the Data. Next() must be called before accessing them. @@ -85,22 +78,11 @@ class Parser : public StructParser * @return #CHIP_NO_ERROR on success * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetData(chip::TLV::TLVReader * const apReader) const; - - /** - * @brief Get a TLVReader for the StatusIB. Next() must be called before accessing them. - * - * @param [in] apStatusIB A pointer to apStatusIB - * - * @return #CHIP_NO_ERROR on success - * # CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a structure - * #CHIP_END_OF_TLV if there is no such element - */ - CHIP_ERROR GetStatusIB(StatusIB::Parser * const apStatusIB) const; + CHIP_ERROR GetData(TLV::TLVReader * const apReader) const; protected: // A recursively callable function to parse a data element and pretty-print it. - CHIP_ERROR ParseData(chip::TLV::TLVReader & aReader, int aDepth) const; + CHIP_ERROR ParseData(TLV::TLVReader & aReader, int aDepth) const; }; class Builder : public StructBuilder @@ -111,14 +93,7 @@ class Builder : public StructBuilder * * @return A reference to CommandPathIB::Builder */ - CommandPathIB::Builder & CreateCommandPathBuilder(); - - /** - * @brief Initialize a StatusIB::Builder for writing into the TLV stream - * - * @return A reference to StatusIB::Builder - */ - StatusIB::Builder & CreateStatusIBBuilder(); + CommandPathIB::Builder & CreatePath(); /** * @brief Mark the end of this CommandDataIB @@ -128,9 +103,8 @@ class Builder : public StructBuilder CommandDataIB::Builder & EndOfCommandDataIB(); private: - CommandPathIB::Builder mCommandPathBuilder; - StatusIB::Builder mStatusIBBuilder; + CommandPathIB::Builder mPath; }; -}; // namespace CommandDataIB -}; // namespace app -}; // namespace chip +} // namespace CommandDataIB +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/CommandList.cpp b/src/app/MessageDef/CommandList.cpp deleted file mode 100644 index 73f33c41f4f55a..00000000000000 --- a/src/app/MessageDef/CommandList.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * Copyright (c) 2016-2017 Nest Labs, Inc. - * 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 CommandList parser and builder in CHIP interaction model - * - */ - -#include "CommandList.h" - -#include "MessageDefHelper.h" - -#include -#include -#include - -#include - -using namespace chip; -using namespace chip::TLV; - -namespace chip { -namespace app { -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR CommandList::Parser::CheckSchemaValidity() const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - size_t NumCommands = 0; - chip::TLV::TLVReader reader; - - PRETTY_PRINT("CommandList ="); - PRETTY_PRINT("["); - - // make a copy of the reader - reader.Init(mReader); - - while (CHIP_NO_ERROR == (err = reader.Next())) - { - VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - { - CommandDataIB::Parser data; - err = data.Init(reader); - SuccessOrExit(err); - - PRETTY_PRINT_INCDEPTH(); - err = data.CheckSchemaValidity(); - SuccessOrExit(err); - - PRETTY_PRINT_DECDEPTH(); - } - - ++NumCommands; - } - - PRETTY_PRINT("],"); - PRETTY_PRINT(""); - - // if we have exhausted this container - if (CHIP_END_OF_TLV == err) - { - // if we have at least one data element - if (NumCommands > 0) - { - err = CHIP_NO_ERROR; - } - } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); - -exit: - - return err; -} -#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - -CommandDataIB::Builder & CommandList::Builder::CreateCommandDataIBBuilder() -{ - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandDataIBBuilder.ResetError(mError)); - - mError = mCommandDataIBBuilder.Init(mpWriter); - -exit: - // on error, mCommandDataIBBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandDataIBBuilder; -} - -CommandList::Builder & CommandList::Builder::EndOfCommandList() -{ - EndOfContainer(); - return *this; -} -}; // namespace app -}; // namespace chip diff --git a/src/app/MessageDef/CommandPathIB.cpp b/src/app/MessageDef/CommandPathIB.cpp index fbda9de0b33507..d0fe5e805bc852 100644 --- a/src/app/MessageDef/CommandPathIB.cpp +++ b/src/app/MessageDef/CommandPathIB.cpp @@ -15,11 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines CommandPathIB parser and builder in CHIP interaction model - * - */ #include "CommandPathIB.h" @@ -39,8 +34,8 @@ namespace app { #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK CHIP_ERROR CommandPathIB::Parser::CheckSchemaValidity() const { - CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; chip::TLV::TLVReader reader; PRETTY_PRINT("CommandPathIB ="); PRETTY_PRINT("{"); @@ -168,7 +163,7 @@ CommandPathIB::Builder & CommandPathIB::Builder::CommandId(const chip::CommandId return *this; } -CommandPathIB::Builder & CommandPathIB::Builder::EndOfCommandPath() +CommandPathIB::Builder & CommandPathIB::Builder::EndOfCommandPathIB() { EndOfContainer(); return *this; diff --git a/src/app/MessageDef/CommandPathIB.h b/src/app/MessageDef/CommandPathIB.h index 3450ac31efeb0a..62296b5da568a5 100644 --- a/src/app/MessageDef/CommandPathIB.h +++ b/src/app/MessageDef/CommandPathIB.h @@ -15,11 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines CommandPathIB parser and builder in CHIP interaction model - * - */ #pragma once @@ -132,9 +127,8 @@ class Builder : public ListBuilder * * @return A reference to *this */ - CommandPathIB::Builder & EndOfCommandPath(); + CommandPathIB::Builder & EndOfCommandPathIB(); }; -}; // namespace CommandPathIB - -}; // namespace app -}; // namespace chip +} // namespace CommandPathIB +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/CommandStatusIB.cpp b/src/app/MessageDef/CommandStatusIB.cpp new file mode 100644 index 00000000000000..463b495e44538c --- /dev/null +++ b/src/app/MessageDef/CommandStatusIB.cpp @@ -0,0 +1,144 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include "CommandStatusIB.h" +#include "MessageDefHelper.h" +#include "StructBuilder.h" +#include "StructParser.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR CommandStatusIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("CommandStatusIB ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kPath): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kPath))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kPath)); + { + CommandPathIB::Parser path; + ReturnErrorOnFailure(path.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(path.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + case to_underlying(Tag::kErrorStatus): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kErrorStatus))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kErrorStatus)); + { + StatusIB::Parser errorStatus; + ReturnErrorOnFailure(errorStatus.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(errorStatus.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kPath)) | (1 << to_underlying(Tag::kErrorStatus)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR CommandStatusIB::Parser::GetPath(CommandPathIB::Parser * const apPath) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kPath)), reader)); + ReturnErrorOnFailure(apPath->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandStatusIB::Parser::GetErrorStatus(StatusIB::Parser * const apErrorStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kErrorStatus)), reader)); + ReturnErrorOnFailure(apErrorStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +CommandPathIB::Builder & CommandStatusIB::Builder::CreatePath() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mPath.Init(mpWriter, to_underlying(Tag::kPath)); + } + return mPath; +} + +StatusIB::Builder & CommandStatusIB::Builder::CreateErrorStatus() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mErrorStatus.Init(mpWriter, to_underlying(Tag::kErrorStatus)); + } + return mErrorStatus; +} + +CommandStatusIB::Builder & CommandStatusIB::Builder::EndOfCommandStatusIB() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/CommandStatusIB.h b/src/app/MessageDef/CommandStatusIB.h new file mode 100644 index 00000000000000..2a785295984d09 --- /dev/null +++ b/src/app/MessageDef/CommandStatusIB.h @@ -0,0 +1,115 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include "CommandPathIB.h" +#include "StructBuilder.h" + +#include "StatusIB.h" +#include "StructParser.h" + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace CommandStatusIB { +enum class Tag : uint8_t +{ + kPath = 0, + kErrorStatus = 1, +}; + +class Parser : public StructParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get a TLVReader for the CommandPathIB. Next() must be called before accessing them. + * + * @param [in] apPath A pointer to apPath + * + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetPath(CommandPathIB::Parser * const apPath) const; + + /** + * @brief Get a TLVReader for the StatusIB. Next() must be called before accessing them. + * + * @param [in] apErrorStatus A pointer to apErrorStatus + * + * @return #CHIP_NO_ERROR on success + * # CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a structure + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetErrorStatus(StatusIB::Parser * const apErrorStatus) const; +}; + +class Builder : public StructBuilder +{ +public: + /** + * @brief Initialize a CommandPathIB::Builder for writing into the TLV stream + * + * @return A reference to CommandPathIB::Builder + */ + CommandPathIB::Builder & CreatePath(); + + /** + * @brief Initialize a StatusIB::Builder for writing into the TLV stream + * + * @return A reference to StatusIB::Builder + */ + StatusIB::Builder & CreateErrorStatus(); + + /** + * @brief Mark the end of this CommandStatusIB + * + * @return A reference to *this + */ + CommandStatusIB::Builder & EndOfCommandStatusIB(); + +private: + CommandPathIB::Builder mPath; + StatusIB::Builder mErrorStatus; +}; +} // namespace CommandStatusIB +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeCommand.cpp b/src/app/MessageDef/InvokeCommand.cpp deleted file mode 100644 index 03213c71caa853..00000000000000 --- a/src/app/MessageDef/InvokeCommand.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * Copyright (c) 2016-2017 Nest Labs, Inc. - * 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 InvokeCommand parser and builder in CHIP interaction model - * - */ - -#include -#include -#include - -#include "InvokeCommand.h" -#include "MessageDefHelper.h" - -#include - -using namespace chip; -using namespace chip::TLV; - -namespace chip { -namespace app { -CHIP_ERROR InvokeCommand::Parser::Init(const chip::TLV::TLVReader & aReader) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // make a copy of the reader here - mReader.Init(aReader); - - VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = mReader.EnterContainer(mOuterContainerType); - -exit: - - return err; -} - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR InvokeCommand::Parser::CheckSchemaValidity() const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; - chip::TLV::TLVReader reader; - CommandList::Parser commandList; - - PRETTY_PRINT("InvokeCommand ="); - PRETTY_PRINT("{"); - - // make a copy of the reader - reader.Init(mReader); - - while (CHIP_NO_ERROR == (err = reader.Next())) - { - const Tag tag = reader.GetTag(); - - if (chip::TLV::ContextTag(kCsTag_CommandList) == tag) - { - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandList)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_CommandList); - VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - commandList.Init(reader); - - PRETTY_PRINT_INCDEPTH(); - - err = commandList.CheckSchemaValidity(); - SuccessOrExit(err); - - PRETTY_PRINT_DECDEPTH(); - } - else - { - PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag); - } - } - - PRETTY_PRINT("}"); - PRETTY_PRINT(""); - - // if we have exhausted this container - if (CHIP_END_OF_TLV == err) - { - // if we have at least the DataList or EventList field - if ((TagPresenceMask & (1 << kCsTag_CommandList))) - { - err = CHIP_NO_ERROR; - } - } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); - -exit: - - return err; -} -#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - -CHIP_ERROR InvokeCommand::Parser::GetCommandList(CommandList::Parser * const apCommandList) const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandList), reader); - SuccessOrExit(err); - - VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = apCommandList->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; -} - -CHIP_ERROR InvokeCommand::Builder::Init(chip::TLV::TLVWriter * const apWriter) -{ - return InitAnonymousStructure(apWriter); -} - -CommandList::Builder & InvokeCommand::Builder::CreateCommandListBuilder() -{ - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandListBuilder.ResetError(mError)); - - mError = mCommandListBuilder.Init(mpWriter, kCsTag_CommandList); - -exit: - // on error, mCommandListBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandListBuilder; -} - -CommandList::Builder & InvokeCommand::Builder::GetCommandListBuilder() -{ - return mCommandListBuilder; -} - -InvokeCommand::Builder & InvokeCommand::Builder::EndOfInvokeCommand() -{ - EndOfContainer(); - return *this; -} -}; // namespace app -}; // namespace chip diff --git a/src/app/MessageDef/InvokeRequestMessage.cpp b/src/app/MessageDef/InvokeRequestMessage.cpp new file mode 100644 index 00000000000000..2ae9b3dc75f3ae --- /dev/null +++ b/src/app/MessageDef/InvokeRequestMessage.cpp @@ -0,0 +1,174 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include +#include +#include + +#include "InvokeRequestMessage.h" +#include "MessageDefHelper.h" + +#include + +namespace chip { +namespace app { +CHIP_ERROR InvokeRequestMessage::Parser::Init(const TLV::TLVReader & aReader) +{ + mReader.Init(aReader); + VerifyOrReturnError(TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeRequestMessage::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeRequestMessage ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kSuppressResponse): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kSuppressResponse))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kSuppressResponse)); +#if CHIP_DETAIL_LOGGING + { + bool suppressResponse; + ReturnErrorOnFailure(reader.Get(suppressResponse)); + PRETTY_PRINT("\tsuppressResponse = %s, ", suppressResponse ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + + case to_underlying(Tag::kTimedRequest): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kTimedRequest))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kTimedRequest)); +#if CHIP_DETAIL_LOGGING + { + bool timedRequest; + ReturnErrorOnFailure(reader.Get(timedRequest)); + PRETTY_PRINT("\ttimedRequest = %s, ", timedRequest ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kInvokeRequests): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kInvokeRequests))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kInvokeRequests)); + { + InvokeRequests::Parser invokeRequests; + ReturnErrorOnFailure(invokeRequests.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeRequests.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kSuppressResponse)) | (1 << to_underlying(Tag::kTimedRequest)) | + (1 << to_underlying(Tag::kInvokeRequests)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeRequestMessage::Parser::GetSuppressResponse(bool * const apSuppressResponse) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apSuppressResponse); +} + +CHIP_ERROR InvokeRequestMessage::Parser::GetTimedRequest(bool * const apTimedRequest) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apTimedRequest); +} + +CHIP_ERROR InvokeRequestMessage::Parser::GetInvokeRequests(InvokeRequests::Parser * const apInvokeRequests) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kInvokeRequests)), reader)); + ReturnErrorOnFailure(apInvokeRequests->Init(reader)); + return CHIP_NO_ERROR; +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::SuppressResponse(const bool aSuppressResponse) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kSuppressResponse)), aSuppressResponse); + } + return *this; +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::TimedRequest(const bool aTimedRequest) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kTimedRequest)), aTimedRequest); + } + return *this; +} + +InvokeRequests::Builder & InvokeRequestMessage::Builder::CreateInvokeRequests() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mInvokeRequests.Init(mpWriter, to_underlying(Tag::kInvokeRequests)); + } + return mInvokeRequests; +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::EndOfInvokeRequestMessage() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeRequestMessage.h b/src/app/MessageDef/InvokeRequestMessage.h new file mode 100644 index 00000000000000..2b25d33684246b --- /dev/null +++ b/src/app/MessageDef/InvokeRequestMessage.h @@ -0,0 +1,136 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "InvokeRequests.h" +#include "StructBuilder.h" +#include "StructParser.h" + +namespace chip { +namespace app { +namespace InvokeRequestMessage { +enum class Tag : uint8_t +{ + kSuppressResponse = 0, + kTimedRequest = 1, + kInvokeRequests = 2, +}; + +class Parser : public StructParser +{ +public: + /** + * @brief Initialize the parser object with TLVReader + * + * @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this request + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(const TLV::TLVReader & aReader); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get SuppressResponse. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetSuppressResponse(bool * const apSuppressResponse) const; + + /** + * @brief Get TimedRequest. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetTimedRequest(bool * const apTimedRequest) const; + + /** + * @brief Get a parser for an InvokeRequests. + * + * @param [in] apInvokeRequests A pointer to the invoke request list parser. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetInvokeRequests(InvokeRequests::Parser * const apInvokeRequests) const; +}; + +class Builder : public StructBuilder +{ +public: + /** + * @brief when sets to true, it means do not send a response to this action + */ + InvokeRequestMessage::Builder & SuppressResponse(const bool aSuppressResponse); + + /** + * @brief This is flag to indication if ths action is part of a timed invoke transaction + */ + InvokeRequestMessage::Builder & TimedRequest(const bool aTimedRequest); + + /** + * @brief Initialize a InvokeRequests::Builder for writing into the TLV stream + * + * @return A reference to InvokeRequests::Builder + */ + InvokeRequests::Builder & CreateInvokeRequests(); + + /** + * @brief Get reference to InvokeRequests::Builder + * + * @return A reference to InvokeRequests::Builder + */ + InvokeRequests::Builder & GetInvokeRequests() { return mInvokeRequests; } + + /** + * @brief Mark the end of this InvokeRequestMessage + * + * @return A reference to *this + */ + InvokeRequestMessage::Builder & EndOfInvokeRequestMessage(); + +private: + InvokeRequests::Builder mInvokeRequests; +}; +}; // namespace InvokeRequestMessage +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeRequests.cpp b/src/app/MessageDef/InvokeRequests.cpp new file mode 100644 index 00000000000000..81608bb34fee09 --- /dev/null +++ b/src/app/MessageDef/InvokeRequests.cpp @@ -0,0 +1,89 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include "InvokeRequests.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeRequests::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + size_t numCommandDatas = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeRequests ="); + PRETTY_PRINT("["); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + { + CommandDataIB::Parser commandData; + ReturnErrorOnFailure(commandData.Init(reader)); + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(commandData.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + + ++numCommandDatas; + } + + PRETTY_PRINT("],"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // if we have at least one data element + if (numCommandDatas > 0) + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CommandDataIB::Builder & InvokeRequests::Builder::CreateCommandData() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mCommandData.Init(mpWriter); + } + return mCommandData; +} + +InvokeRequests::Builder & InvokeRequests::Builder::EndOfInvokeRequests() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/CommandList.h b/src/app/MessageDef/InvokeRequests.h similarity index 77% rename from src/app/MessageDef/CommandList.h rename to src/app/MessageDef/InvokeRequests.h index ebf193a1da85d6..e81be842b1b530 100644 --- a/src/app/MessageDef/CommandList.h +++ b/src/app/MessageDef/InvokeRequests.h @@ -1,7 +1,6 @@ /** * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2016-2017 Nest Labs, Inc. + * Copyright (c) 2021 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. @@ -15,18 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines CommandList parser and builder in CHIP interaction model - * - */ #pragma once -#include "ArrayBuilder.h" -#include "ArrayParser.h" -#include "CommandDataIB.h" - #include #include #include @@ -34,9 +24,13 @@ #include #include +#include "ArrayBuilder.h" +#include "ArrayParser.h" +#include "CommandDataIB.h" + namespace chip { namespace app { -namespace CommandList { +namespace InvokeRequests { class Parser : public ArrayParser { public: @@ -66,23 +60,23 @@ class Builder : public ArrayBuilder * * @return A reference to CommandDataIB::Builder */ - CommandDataIB::Builder & CreateCommandDataIBBuilder(); + CommandDataIB::Builder & CreateCommandData(); /** * @return A reference to CommandDataIB::Builder */ - CommandDataIB::Builder & GetCommandDataIBBuilder() { return mCommandDataIBBuilder; }; + CommandDataIB::Builder & GetCommandData() { return mCommandData; }; /** - * @brief Mark the end of this CommandList + * @brief Mark the end of this InvokeRequests * * @return A reference to *this */ - CommandList::Builder & EndOfCommandList(); + InvokeRequests::Builder & EndOfInvokeRequests(); private: - CommandDataIB::Builder mCommandDataIBBuilder; + CommandDataIB::Builder mCommandData; }; -}; // namespace CommandList -}; // namespace app -}; // namespace chip +} // namespace InvokeRequests +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeResponseIB.cpp b/src/app/MessageDef/InvokeResponseIB.cpp new file mode 100644 index 00000000000000..5ce38453e5e66a --- /dev/null +++ b/src/app/MessageDef/InvokeResponseIB.cpp @@ -0,0 +1,151 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include +#include +#include + +#include "InvokeResponseIB.h" +#include "MessageDefHelper.h" + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponseIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponseIB ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kCommand): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kCommand))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kCommand)); + { + CommandDataIB::Parser command; + ReturnErrorOnFailure(command.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(command.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + case to_underlying(Tag::kStatus): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kStatus))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kStatus)); + { + CommandStatusIB::Parser status; + ReturnErrorOnFailure(status.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(status.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // check for at most field: + const int CheckCommandField = 1 << to_underlying(Tag::kCommand); + const int CheckStatusField = (1 << to_underlying(Tag::kStatus)); + + if ((TagPresenceMask & CheckCommandField) == CheckCommandField && (TagPresenceMask & CheckStatusField) == CheckStatusField) + { + // kPath and kErrorStatus both exist + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB; + } + else if ((TagPresenceMask & CheckCommandField) != CheckCommandField && + (TagPresenceMask & CheckStatusField) != CheckStatusField) + { + // kPath and kErrorStatus not exist + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB; + } + else + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeResponseIB::Parser::GetCommand(CommandDataIB::Parser * const apCommand) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kCommand)), reader)); + ReturnErrorOnFailure(apCommand->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR InvokeResponseIB::Parser::GetStatus(CommandStatusIB::Parser * const apStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kStatus)), reader)); + ReturnErrorOnFailure(apStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +CommandDataIB::Builder & InvokeResponseIB::Builder::CreateCommand() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mCommand.Init(mpWriter, to_underlying(Tag::kCommand)); + } + return mCommand; +} + +CommandStatusIB::Builder & InvokeResponseIB::Builder::CreateStatus() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mStatus.Init(mpWriter, to_underlying(Tag::kStatus)); + } + return mStatus; +} + +InvokeResponseIB::Builder & InvokeResponseIB::Builder::EndOfInvokeResponseIB() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeCommand.h b/src/app/MessageDef/InvokeResponseIB.h similarity index 55% rename from src/app/MessageDef/InvokeCommand.h rename to src/app/MessageDef/InvokeResponseIB.h index 763118aab8586f..83de7bc7810b14 100644 --- a/src/app/MessageDef/InvokeCommand.h +++ b/src/app/MessageDef/InvokeResponseIB.h @@ -1,7 +1,6 @@ /** * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2016-2017 Nest Labs, Inc. + * Copyright (c) 2021 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. @@ -15,11 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines InvokeCommand parser and builder in CHIP interaction model - * - */ #pragma once @@ -30,31 +24,23 @@ #include #include -#include "Builder.h" #include "CommandDataIB.h" -#include "CommandList.h" -#include "Parser.h" +#include "CommandStatusIB.h" +#include "StructBuilder.h" +#include "StructParser.h" namespace chip { namespace app { -namespace InvokeCommand { -enum +namespace InvokeResponseIB { +enum class Tag : uint8_t { - kCsTag_CommandList = 0, + kCommand = 0, + kStatus = 1, }; -class Parser : public chip::app::Parser +class Parser : public StructParser { public: - /** - * @brief Initialize the parser object with TLVReader - * - * @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this request - * - * @return #CHIP_NO_ERROR on success - */ - CHIP_ERROR Init(const chip::TLV::TLVReader & aReader); - #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK /** * @brief Roughly verify the message is correctly formed @@ -73,52 +59,64 @@ class Parser : public chip::app::Parser #endif /** - * @brief Get a parser for a CommandList. + * @brief Get a parser for a Command. * - * @param [in] apCommandList A pointer to the command list parser. + * @param [in] apCommand A pointer to the CommandDataIB parser. * * @return #CHIP_NO_ERROR on success * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetCommandList(CommandList::Parser * const apCommandList) const; -}; + CHIP_ERROR GetCommand(CommandDataIB::Parser * const apCommand) const; -class Builder : public chip::app::Builder -{ -public: /** - * @brief Initialize a InvokeCommand::Builder for writing into a TLV stream + * @brief Get a parser for a Status. * - * @param [in] apWriter A pointer to TLVWriter + * @param [in] apCommand A pointer to the CommandStatusIB parser. * * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); + CHIP_ERROR GetStatus(CommandStatusIB::Parser * const apStatus) const; +}; +class Builder : public StructBuilder +{ +public: /** - * @brief Initialize a CommandList::Builder for writing into the TLV stream + * @brief Initialize a CommandDataIB::Builder for writing into the TLV stream * - * @return A reference to CommandList::Builder + * @return A reference to CommandDataIB::Builder + */ + CommandDataIB::Builder & CreateCommand(); + + /** + * @return A reference to CommandDataIB::Builder + */ + CommandDataIB::Builder & GetCommand() { return mCommand; } + + /** + * @return A reference to CommandStatusIB::Builder */ - CommandList::Builder & CreateCommandListBuilder(); + CommandStatusIB::Builder & GetStatus() { return mStatus; } /** - * @brief Get reference to CommandList::Builder + * @brief Initialize a CommandStatusIB::Builder for writing into the TLV stream * - * @return A reference to CommandList::Builder + * @return A reference to CommandStatusIB::Builder */ - CommandList::Builder & GetCommandListBuilder(); + CommandStatusIB::Builder & CreateStatus(); /** * @brief Mark the end of this InvokeCommand * * @return A reference to *this */ - InvokeCommand::Builder & EndOfInvokeCommand(); + InvokeResponseIB::Builder & EndOfInvokeResponseIB(); private: - CommandList::Builder mCommandListBuilder; + CommandDataIB::Builder mCommand; + CommandStatusIB::Builder mStatus; }; -}; // namespace InvokeCommand -}; // namespace app -}; // namespace chip +} // namespace InvokeResponseIB +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeResponseMessage.cpp b/src/app/MessageDef/InvokeResponseMessage.cpp new file mode 100644 index 00000000000000..62d008d577f893 --- /dev/null +++ b/src/app/MessageDef/InvokeResponseMessage.cpp @@ -0,0 +1,138 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include +#include +#include + +#include "InvokeResponseMessage.h" +#include "MessageDefHelper.h" + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponseMessage::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponseMessage ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kSuppressResponse): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kSuppressResponse))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kSuppressResponse)); +#if CHIP_DETAIL_LOGGING + { + bool suppressResponse; + ReturnErrorOnFailure(reader.Get(suppressResponse)); + PRETTY_PRINT("\tsuppressResponse = %s, ", suppressResponse ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kInvokeResponses): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kInvokeResponses))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kInvokeResponses)); + { + InvokeResponses::Parser invokeResponses; + ReturnErrorOnFailure(invokeResponses.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeResponses.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kSuppressResponse)) | (1 << to_underlying(Tag::kInvokeResponses)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeResponseMessage::Parser::GetSuppressResponse(bool * const apSuppressResponse) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apSuppressResponse); +} + +CHIP_ERROR InvokeResponseMessage::Parser::GetInvokeResponses(InvokeResponses::Parser * const apStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kInvokeResponses)), reader)); + ReturnErrorOnFailure(apStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::SuppressResponse(const bool aSuppressResponse) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kSuppressResponse)), aSuppressResponse); + } + return *this; +} + +InvokeResponses::Builder & InvokeResponseMessage::Builder::CreateInvokeResponses() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mInvokeResponses.Init(mpWriter, to_underlying(Tag::kInvokeResponses)); + } + return mInvokeResponses; +} + +InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::EndOfInvokeResponseMessage() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeResponseMessage.h b/src/app/MessageDef/InvokeResponseMessage.h new file mode 100644 index 00000000000000..d9aa0adab0e6c5 --- /dev/null +++ b/src/app/MessageDef/InvokeResponseMessage.h @@ -0,0 +1,114 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "InvokeResponses.h" +#include "StructBuilder.h" +#include "StructParser.h" + +namespace chip { +namespace app { +namespace InvokeResponseMessage { +enum class Tag : uint8_t +{ + kSuppressResponse = 0, + kInvokeResponses = 1, +}; + +class Parser : public StructParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get SuppressResponse. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetSuppressResponse(bool * const apSuppressResponse) const; + + /** + * @brief Get a parser for a InvokeResponse. + * + * @param [in] apInvokeResponses A pointer to the invoke response list parser. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetInvokeResponses(InvokeResponses::Parser * const apInvokeResponses) const; +}; + +class Builder : public StructBuilder +{ +public: + /** + * @brief This is set to 'true' by the subscriber to indicate preservation of previous subscriptions. If omitted, it implies + * 'false' as a value. + */ + InvokeResponseMessage::Builder & SuppressResponse(const bool aSuppressResponse); + + /** + * @brief Initialize a InvokeResponses::Builder for writing into the TLV stream + * + * @return A reference to InvokeResponses::Builder + */ + InvokeResponses::Builder & CreateInvokeResponses(); + + /** + * @brief Get reference to InvokeResponses::Builder + * + * @return A reference to InvokeResponses::Builder + */ + InvokeResponses::Builder & GetInvokeResponses() { return mInvokeResponses; } + + /** + * @brief Mark the end of this InvokeResponseMessage + * + * @return A reference to *this + */ + InvokeResponseMessage::Builder & EndOfInvokeResponseMessage(); + +private: + InvokeResponses::Builder mInvokeResponses; +}; +} // namespace InvokeResponseMessage +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeResponses.cpp b/src/app/MessageDef/InvokeResponses.cpp new file mode 100644 index 00000000000000..6380beacd8857a --- /dev/null +++ b/src/app/MessageDef/InvokeResponses.cpp @@ -0,0 +1,89 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#include "InvokeResponses.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponses::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + size_t numInvokeResponses = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponses ="); + PRETTY_PRINT("["); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + { + InvokeResponseIB::Parser invokeResponse; + ReturnErrorOnFailure(invokeResponse.Init(reader)); + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeResponse.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + + ++numInvokeResponses; + } + + PRETTY_PRINT("],"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // if we have at least one data element + if (numInvokeResponses > 0) + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +InvokeResponseIB::Builder & InvokeResponses::Builder::CreateInvokeResponse() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mInvokeResponse.Init(mpWriter); + } + return mInvokeResponse; +} + +InvokeResponses::Builder & InvokeResponses::Builder::EndOfInvokeResponses() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/InvokeResponses.h b/src/app/MessageDef/InvokeResponses.h new file mode 100644 index 00000000000000..b4759c059575a7 --- /dev/null +++ b/src/app/MessageDef/InvokeResponses.h @@ -0,0 +1,82 @@ +/** + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "ArrayBuilder.h" +#include "ArrayParser.h" +#include "InvokeResponseIB.h" + +namespace chip { +namespace app { +namespace InvokeResponses { +class Parser : public ArrayParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif +}; + +class Builder : public ArrayBuilder +{ +public: + /** + * @brief Initialize a InvokeResponseIB::Builder for writing into the TLV stream + * + * @return A reference to InvokeResponseIB::Builder + */ + InvokeResponseIB::Builder & CreateInvokeResponse(); + + /** + * @return A reference to InvokeResponseIB::Builder + */ + InvokeResponseIB::Builder & GetInvokeResponse() { return mInvokeResponse; }; + + /** + * @brief Mark the end of this InvokeResponses + * + * @return A reference to *this + */ + InvokeResponses::Builder & EndOfInvokeResponses(); + +private: + InvokeResponseIB::Builder mInvokeResponse; +}; +} // namespace InvokeResponses +} // namespace app +} // namespace chip diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index 7089368623d244..5826a0ad877804 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -332,7 +332,8 @@ namespace { FabricInfo gFabricBeingCommissioned; -CHIP_ERROR SendNOCResponse(app::Command * commandObj, EmberAfNodeOperationalCertStatus status, uint8_t index, CharSpan debug_text) +CHIP_ERROR SendNOCResponse(app::CommandHandler * commandObj, EmberAfNodeOperationalCertStatus status, uint8_t index, + CharSpan debug_text) { app::CommandPathParams cmdParams = { emberAfCurrentEndpoint(), /* group id */ 0, OperationalCredentials::Id, Commands::NOCResponse::Id, (app::CommandPathFlags::kEndpointIdValid) }; diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp index 3586e30541b2b8..b248171eb30427 100644 --- a/src/app/tests/TestCommandInteraction.cpp +++ b/src/app/tests/TestCommandInteraction.cpp @@ -61,6 +61,12 @@ constexpr CommandId kTestNonExistCommandId = 0; } // namespace namespace app { +bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) +{ + // Mock cluster catalog, only support one command on one cluster on one endpoint. + return (aCommandPath.mEndpointId == kTestEndpointId && aCommandPath.mClusterId == kTestClusterId && + aCommandPath.mCommandId != kTestNonExistCommandId); +} void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj) @@ -139,13 +145,6 @@ class MockCommandHandlerCallback : public CommandHandler::Callback int onFinalCalledTimes = 0; } mockCommandHandlerDelegate; -bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) -{ - // Mock cluster catalog, only support one command on one cluster on one endpoint. - return (aCommandPath.mEndpointId == kTestEndpointId && aCommandPath.mClusterId == kTestClusterId && - aCommandPath.mCommandId != kTestNonExistCommandId); -} - class TestCommandInteraction { public: @@ -174,11 +173,16 @@ class TestCommandInteraction } private: - static void GenerateReceivedCommand(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, - bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, - ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); - static void AddCommandDataIB(nlTestSuite * apSuite, void * apContext, Command * apCommand, bool aNeedStatusCode, - CommandId aCommandId = kTestCommandId); + static void GenerateInvokeRequest(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, + ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); + static void GenerateInvokeResponse(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, + ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); + static void AddInvokeRequestData(nlTestSuite * apSuite, void * apContext, CommandSender * apCommandSender, + CommandId aCommandId = kTestCommandId); + static void AddInvokeResponseData(nlTestSuite * apSuite, void * apContext, CommandHandler * apCommandHandler, + bool aNeedStatusCode, CommandId aCommandId = kTestCommandId); static void ValidateCommandHandlerWithSendCommand(nlTestSuite * apSuite, void * apContext, bool aNeedStatusCode); }; @@ -198,36 +202,95 @@ CommandPathParams MakeTestCommandPath(CommandId aCommandId = kTestCommandId) return CommandPathParams(kTestEndpointId, 0, kTestClusterId, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid)); } -void TestCommandInteraction::GenerateReceivedCommand(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, - bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, - CommandId aCommandId) +void TestCommandInteraction::GenerateInvokeRequest(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, + CommandId aCommandId) + +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Builder invokeRequestMessageBuilder; + System::PacketBufferTLVWriter writer; + writer.Init(std::move(aPayload)); + + err = invokeRequestMessageBuilder.Init(&writer); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + invokeRequestMessageBuilder.SuppressResponse(true).TimedRequest(true); + InvokeRequests::Builder invokeRequests = invokeRequestMessageBuilder.CreateInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); + + CommandDataIB::Builder commandDataIBBuilder = invokeRequests.CreateCommandData(); + NL_TEST_ASSERT(apSuite, invokeRequests.GetError() == CHIP_NO_ERROR); + + CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreatePath(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); + + commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPathIB(); + NL_TEST_ASSERT(apSuite, commandPathBuilder.GetError() == CHIP_NO_ERROR); + + if (aNeedCommandData) + { + chip::TLV::TLVWriter * pWriter = commandDataIBBuilder.GetWriter(); + chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = pWriter->EndContainer(dummyType); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + } + + commandDataIBBuilder.EndOfCommandDataIB(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); + + invokeRequests.EndOfInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequests.GetError() == CHIP_NO_ERROR); + + invokeRequestMessageBuilder.EndOfInvokeRequestMessage(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); + + err = writer.Finalize(&aPayload); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void TestCommandInteraction::GenerateInvokeResponse(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, + CommandId aCommandId) { CHIP_ERROR err = CHIP_NO_ERROR; - InvokeCommand::Builder invokeCommandBuilder; + InvokeResponseMessage::Builder invokeResponseMessageBuilder; System::PacketBufferTLVWriter writer; writer.Init(std::move(aPayload)); - err = invokeCommandBuilder.Init(&writer); + err = invokeResponseMessageBuilder.Init(&writer); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - CommandList::Builder commandList = invokeCommandBuilder.CreateCommandListBuilder(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); + invokeResponseMessageBuilder.SuppressResponse(true); + InvokeResponses::Builder invokeResponses = invokeResponseMessageBuilder.CreateInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); - CommandDataIB::Builder commandDataIBBuilder = commandList.CreateCommandDataIBBuilder(); - NL_TEST_ASSERT(apSuite, commandList.GetError() == CHIP_NO_ERROR); + InvokeResponseIB::Builder invokeResponseIBBuilder = invokeResponses.CreateInvokeResponse(); + NL_TEST_ASSERT(apSuite, invokeResponses.GetError() == CHIP_NO_ERROR); + + CommandDataIB::Builder commandDataIBBuilder = invokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreateCommandPathBuilder(); + CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreatePath(); NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPath(); + commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPathIB(); NL_TEST_ASSERT(apSuite, commandPathBuilder.GetError() == CHIP_NO_ERROR); if (aNeedCommandData) { chip::TLV::TLVWriter * pWriter = commandDataIBBuilder.GetWriter(); chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; - err = pWriter->StartContainer(chip::TLV::ContextTag(CommandDataIB::kCsTag_Data), chip::TLV::kTLVType_Structure, dummyType); + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); @@ -240,18 +303,39 @@ void TestCommandInteraction::GenerateReceivedCommand(nlTestSuite * apSuite, void commandDataIBBuilder.EndOfCommandDataIB(); NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - commandList.EndOfCommandList(); - NL_TEST_ASSERT(apSuite, commandList.GetError() == CHIP_NO_ERROR); + invokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, invokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); - invokeCommandBuilder.EndOfInvokeCommand(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); + invokeResponses.EndOfInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponses.GetError() == CHIP_NO_ERROR); + + invokeResponseMessageBuilder.EndOfInvokeResponseMessage(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); err = writer.Finalize(&aPayload); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } -void TestCommandInteraction::AddCommandDataIB(nlTestSuite * apSuite, void * apContext, Command * apCommand, bool aNeedStatusCode, - CommandId aCommandId) +void TestCommandInteraction::AddInvokeRequestData(nlTestSuite * apSuite, void * apContext, CommandSender * apCommandSender, + CommandId aCommandId) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + auto commandPathParams = MakeTestCommandPath(aCommandId); + + err = apCommandSender->PrepareCommand(commandPathParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + chip::TLV::TLVWriter * writer = apCommandSender->GetCommandDataIBTLVWriter(); + + err = writer->PutBoolean(chip::TLV::ContextTag(1), true); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = apCommandSender->FinishCommand(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void TestCommandInteraction::AddInvokeResponseData(nlTestSuite * apSuite, void * apContext, CommandHandler * apCommandHandler, + bool aNeedStatusCode, CommandId aCommandId) { CHIP_ERROR err = CHIP_NO_ERROR; auto commandPathParams = MakeTestCommandPath(aCommandId); @@ -262,19 +346,19 @@ void TestCommandInteraction::AddCommandDataIB(nlTestSuite * apSuite, void * apCo 3, // ClusterId 4 // CommandId ); - apCommand->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); + apCommandHandler->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); } else { - err = apCommand->PrepareCommand(commandPathParams); + err = apCommandHandler->PrepareCommand(commandPathParams); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - chip::TLV::TLVWriter * writer = apCommand->GetCommandDataIBTLVWriter(); + chip::TLV::TLVWriter * writer = apCommandHandler->GetCommandDataIBTLVWriter(); err = writer->PutBoolean(chip::TLV::ContextTag(1), true); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = apCommand->FinishCommand(); + err = apCommandHandler->FinishCommand(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } } @@ -318,12 +402,12 @@ void TestCommandInteraction::TestCommandSenderWithSendCommand(nlTestSuite * apSu System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - AddCommandDataIB(apSuite, apContext, &commandSender, false); + AddInvokeRequestData(apSuite, apContext, &commandSender); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - GenerateReceivedCommand(apSuite, apContext, buf, true /*aNeedCommandData*/); - err = commandSender.ProcessCommandMessage(std::move(buf), Command::CommandRoleId::SenderId); + GenerateInvokeResponse(apSuite, apContext, buf, true /*aNeedCommandData*/); + err = commandSender.ProcessInvokeResponse(std::move(buf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -356,8 +440,8 @@ void TestCommandInteraction::TestCommandSenderWithProcessReceivedMsg(nlTestSuite System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - GenerateReceivedCommand(apSuite, apContext, buf, true /*aNeedCommandData*/); - err = commandSender.ProcessCommandMessage(std::move(buf), Command::CommandRoleId::SenderId); + GenerateInvokeResponse(apSuite, apContext, buf, true /*aNeedCommandData*/); + err = commandSender.ProcessInvokeResponse(std::move(buf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -371,19 +455,19 @@ void TestCommandInteraction::ValidateCommandHandlerWithSendCommand(nlTestSuite * TestExchangeDelegate delegate; commandHandler.mpExchangeCtx = ctx.NewExchangeToAlice(&delegate); - AddCommandDataIB(apSuite, apContext, &commandHandler, aNeedStatusCode); + AddInvokeResponseData(apSuite, apContext, &commandHandler, aNeedStatusCode); err = commandHandler.Finalize(commandPacket); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK chip::System::PacketBufferTLVReader reader; - InvokeCommand::Parser invokeCommandParser; + InvokeResponseMessage::Parser invokeResponseMessageParser; reader.Init(std::move(commandPacket)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.Init(reader); + err = invokeResponseMessageParser.Init(reader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.CheckSchemaValidity(); + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -425,13 +509,13 @@ void TestCommandInteraction::TestCommandHandlerCommandDataEncoding(nlTestSuite * #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK chip::System::PacketBufferTLVReader reader; - InvokeCommand::Parser invokeCommandParser; + InvokeResponseMessage::Parser invokeResponseMessageParser; reader.Init(std::move(commandPacket)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.Init(reader); + err = invokeResponseMessageParser.Init(reader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.CheckSchemaValidity(); + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -448,8 +532,8 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedMsg(nlTestSuit app::CommandHandler commandHandler(&mockCommandHandlerDelegate); System::PacketBufferHandle commandDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, true /*aNeedCommandData*/); - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, true /*aNeedCommandData*/); + err = commandHandler.ProcessInvokeRequest(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -460,13 +544,13 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedNotExistComman System::PacketBufferHandle commandDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); // Use some invalid endpoint / cluster / command. - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/, 0xDE /* endpoint */, - 0xADBE /* cluster */, 0xEF /* command */); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/, 0xDE /* endpoint */, 0xADBE /* cluster */, + 0xEF /* command */); // TODO: Need to find a way to get the response instead of only check if a function on key path is called. // We should not reach CommandDispatch if requested command does not exist. chip::isCommandDispatched = false; - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + err = commandHandler.ProcessInvokeRequest(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, !chip::isCommandDispatched); } @@ -478,9 +562,9 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedEmptyDataMsg(n chip::isCommandDispatched = false; - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/); - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + err = commandHandler.ProcessInvokeRequest(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && chip::isCommandDispatched); } @@ -492,8 +576,9 @@ void TestCommandInteraction::TestCommandSenderCommandSuccessResponseFlow(nlTestS mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false); + AddInvokeRequestData(apSuite, apContext, &commandSender); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 1 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -511,8 +596,9 @@ void TestCommandInteraction::TestCommandSenderCommandSpecificResponseFlow(nlTest mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestCommandIdCommandSpecificResponse); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestCommandIdCommandSpecificResponse); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 1 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -530,8 +616,9 @@ void TestCommandInteraction::TestCommandSenderCommandFailureResponseFlow(nlTestS mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestNonExistCommandId); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestNonExistCommandId); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 0 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -557,8 +644,9 @@ void TestCommandInteraction::TestCommandSenderAbruptDestruction(nlTestSuite * ap { app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestCommandIdCommandSpecificResponse); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestCommandIdCommandSpecificResponse); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); // diff --git a/src/app/tests/TestMessageDef.cpp b/src/app/tests/TestMessageDef.cpp index bd160f8f0db238..2b2e68aa802f20 100644 --- a/src/app/tests/TestMessageDef.cpp +++ b/src/app/tests/TestMessageDef.cpp @@ -23,10 +23,9 @@ */ #include -#include -#include #include -#include +#include +#include #include #include #include @@ -246,7 +245,7 @@ void ParseEventPaths(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) void BuildCommandPath(nlTestSuite * apSuite, CommandPathIB::Builder & aCommandPathBuilder) { - aCommandPathBuilder.EndpointId(1).ClusterId(3).CommandId(4).EndOfCommandPath(); + aCommandPathBuilder.EndpointId(1).ClusterId(3).CommandId(4).EndOfCommandPathIB(); NL_TEST_ASSERT(apSuite, aCommandPathBuilder.GetError() == CHIP_NO_ERROR); } @@ -592,7 +591,7 @@ void BuildCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Builder & aCommand { CHIP_ERROR err = CHIP_NO_ERROR; - CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreateCommandPathBuilder(); + CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreatePath(); NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); BuildCommandPath(apSuite, commandPathBuilder); @@ -600,7 +599,8 @@ void BuildCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Builder & aCommand { chip::TLV::TLVWriter * pWriter = aCommandDataIBBuilder.GetWriter(); chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; - err = pWriter->StartContainer(chip::TLV::ContextTag(CommandDataIB::kCsTag_Data), chip::TLV::kTLVType_Structure, dummyType); + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); @@ -622,7 +622,7 @@ void ParseCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandD err = aCommandDataIBParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif - err = aCommandDataIBParser.GetCommandPath(&commandPathParser); + err = aCommandDataIBParser.GetPath(&commandPathParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); { @@ -644,55 +644,212 @@ void ParseCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandD } } -void BuildCommandDataIBWithStatusCode(nlTestSuite * apSuite, CommandDataIB::Builder & aCommandDataIBBuilder) +void BuildCommandStatusIB(nlTestSuite * apSuite, CommandStatusIB::Builder & aCommandStatusIBBuilder) { - CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreateCommandPathBuilder(); - NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); + CommandPathIB::Builder commandPathBuilder = aCommandStatusIBBuilder.CreatePath(); + NL_TEST_ASSERT(apSuite, aCommandStatusIBBuilder.GetError() == CHIP_NO_ERROR); BuildCommandPath(apSuite, commandPathBuilder); - StatusIB::Builder statusIBBuilder = aCommandDataIBBuilder.CreateStatusIBBuilder(); + StatusIB::Builder statusIBBuilder = aCommandStatusIBBuilder.CreateErrorStatus(); NL_TEST_ASSERT(apSuite, statusIBBuilder.GetError() == CHIP_NO_ERROR); BuildStatusIB(apSuite, statusIBBuilder); - aCommandDataIBBuilder.EndOfCommandDataIB(); - NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); + aCommandStatusIBBuilder.EndOfCommandStatusIB(); + NL_TEST_ASSERT(apSuite, aCommandStatusIBBuilder.GetError() == CHIP_NO_ERROR); } -void ParseCommandDataIBWithStatusCode(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandDataIBParser) +void ParseCommandStatusIB(nlTestSuite * apSuite, CommandStatusIB::Parser & aCommandStatusIBParser) { CHIP_ERROR err = CHIP_NO_ERROR; CommandPathIB::Parser commandPathParser; - StatusIB::Parser StatusIBParser; + StatusIB::Parser statusParser; #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = aCommandDataIBParser.CheckSchemaValidity(); + err = aCommandStatusIBParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif - err = aCommandDataIBParser.GetCommandPath(&commandPathParser); + err = aCommandStatusIBParser.GetPath(&commandPathParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = aCommandDataIBParser.GetStatusIB(&StatusIBParser); + err = aCommandStatusIBParser.GetErrorStatus(&statusParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } -void BuildCommandList(nlTestSuite * apSuite, CommandList::Builder & aCommandListBuilder) +void BuildWrongInvokeResponseIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) { - CommandDataIB::Builder commandDataIBBuilder = aCommandListBuilder.CreateCommandDataIBBuilder(); - NL_TEST_ASSERT(apSuite, aCommandListBuilder.GetError() == CHIP_NO_ERROR); - BuildCommandDataIB(apSuite, commandDataIBBuilder); + CommandDataIB::Builder commandDataBuilder = aInvokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, commandDataBuilder); + CommandStatusIB::Builder commandStatusBuilder = aInvokeResponseIBBuilder.CreateStatus(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandStatusIB(apSuite, commandStatusBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void BuildInvokeResponseIBWithCommandDataIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) +{ + CommandDataIB::Builder commandDataBuilder = aInvokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, commandDataBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void BuildInvokeResponseIBWithCommandStatusIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) +{ + CommandStatusIB::Builder commandStatusBuilder = aInvokeResponseIBBuilder.CreateStatus(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandStatusIB(apSuite, commandStatusBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeResponseIBWithCommandDataIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + err = aInvokeResponseIBParser.GetCommand(&commandDataParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void ParseInvokeResponseIBWithCommandStatusIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + err = aInvokeResponseIBParser.GetStatus(&statusIBParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void ParseWrongInvokeResponseIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + CHIP_ERROR err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err != CHIP_NO_ERROR); +#endif +} + +void BuildInvokeRequests(nlTestSuite * apSuite, InvokeRequests::Builder & aInvokeRequestsBuilder) +{ + CommandDataIB::Builder aCommandDataIBBuilder = aInvokeRequestsBuilder.CreateCommandData(); + NL_TEST_ASSERT(apSuite, aInvokeRequestsBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, aCommandDataIBBuilder); + + aInvokeRequestsBuilder.EndOfInvokeRequests(); + NL_TEST_ASSERT(apSuite, aInvokeRequestsBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeRequests(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequests::Parser invokeRequestsParser; + err = invokeRequestsParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeRequestsParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeResponses(nlTestSuite * apSuite, InvokeResponses::Builder & aInvokeResponsesBuilder) +{ + InvokeResponseIB::Builder invokeResponseIBBuilder = aInvokeResponsesBuilder.CreateInvokeResponse(); + NL_TEST_ASSERT(apSuite, aInvokeResponsesBuilder.GetError() == CHIP_NO_ERROR); + BuildInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBBuilder); - aCommandListBuilder.EndOfCommandList(); - NL_TEST_ASSERT(apSuite, aCommandListBuilder.GetError() == CHIP_NO_ERROR); + aInvokeResponsesBuilder.EndOfInvokeResponses(); + NL_TEST_ASSERT(apSuite, aInvokeResponsesBuilder.GetError() == CHIP_NO_ERROR); } -void ParseCommandList(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +void ParseInvokeResponses(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) { CHIP_ERROR err = CHIP_NO_ERROR; - CommandList::Parser commandListParser; - err = commandListParser.Init(aReader); + InvokeResponses::Parser invokeResponsesParser; + err = invokeResponsesParser.Init(aReader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = commandListParser.CheckSchemaValidity(); + err = invokeResponsesParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Builder invokeRequestMessageBuilder; + err = invokeRequestMessageBuilder.Init(&aWriter); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + invokeRequestMessageBuilder.SuppressResponse(true); + invokeRequestMessageBuilder.TimedRequest(true); + InvokeRequests::Builder invokeRequestsBuilder = invokeRequestMessageBuilder.CreateInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequestsBuilder.GetError() == CHIP_NO_ERROR); + + BuildInvokeRequests(apSuite, invokeRequestsBuilder); + + invokeRequestMessageBuilder.EndOfInvokeRequestMessage(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Parser invokeRequestMessageParser; + err = invokeRequestMessageParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + bool suppressResponse = false; + bool timedRequest = false; + invokeRequestMessageParser.GetSuppressResponse(&suppressResponse); + invokeRequestMessageParser.GetTimedRequest(&timedRequest); + NL_TEST_ASSERT(apSuite, suppressResponse == true); + NL_TEST_ASSERT(apSuite, timedRequest == true); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeRequestMessageParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeResponseMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseMessage::Builder invokeResponseMessageBuilder; + err = invokeResponseMessageBuilder.Init(&aWriter); + + invokeResponseMessageBuilder.SuppressResponse(true); + InvokeResponses::Builder invokeResponsesBuilder = invokeResponseMessageBuilder.CreateInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); + + BuildInvokeResponses(apSuite, invokeResponsesBuilder); + + invokeResponseMessageBuilder.EndOfInvokeResponseMessage(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeResponseMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseMessage::Parser invokeResponseMessageParser; + err = invokeResponseMessageParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + bool suppressResponse = false; + invokeResponseMessageParser.GetSuppressResponse(&suppressResponse); + NL_TEST_ASSERT(apSuite, suppressResponse == true); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -755,40 +912,6 @@ void ParseReportDataMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aReade NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && moreChunkedMessages); } -void BuildInvokeCommand(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - InvokeCommand::Builder invokeCommandBuilder; - - err = invokeCommandBuilder.Init(&aWriter); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - - CommandList::Builder commandList = invokeCommandBuilder.CreateCommandListBuilder(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); - BuildCommandList(apSuite, commandList); - - invokeCommandBuilder.EndOfInvokeCommand(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); -} - -void ParseInvokeCommand(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - InvokeCommand::Parser invokeCommandParser; - CommandList::Parser commandListParser; - - err = invokeCommandParser.Init(aReader); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = invokeCommandParser.CheckSchemaValidity(); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); -#endif - err = invokeCommandParser.GetCommandList(&commandListParser); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); -} - void BuildReadRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1233,7 +1356,7 @@ void EventPathsTest(nlTestSuite * apSuite, void * apContext) ParseEventPaths(apSuite, reader); } -void CommandPathTest(nlTestSuite * apSuite, void * apContext) +void CommandPathIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; chip::System::PacketBufferTLVWriter writer; @@ -1463,16 +1586,16 @@ void CommandDataIBTest(nlTestSuite * apSuite, void * apContext) ParseCommandDataIB(apSuite, commandDataIBParser); } -void CommandDataIBWithStatusCodeTest(nlTestSuite * apSuite, void * apContext) +void CommandStatusIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; - CommandDataIB::Builder commandDataIBBuilder; - CommandDataIB::Parser commandDataIBParser; + CommandStatusIB::Builder commandStatusIBBuilder; + CommandStatusIB::Parser commandStatusIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - commandDataIBBuilder.Init(&writer); - BuildCommandDataIBWithStatusCode(apSuite, commandDataIBBuilder); + commandStatusIBBuilder.Init(&writer); + BuildCommandStatusIB(apSuite, commandStatusIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1483,19 +1606,20 @@ void CommandDataIBWithStatusCodeTest(nlTestSuite * apSuite, void * apContext) err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - commandDataIBParser.Init(reader); - ParseCommandDataIBWithStatusCode(apSuite, commandDataIBParser); + commandStatusIBParser.Init(reader); + ParseCommandStatusIB(apSuite, commandStatusIBParser); } -void CommandListTest(nlTestSuite * apSuite, void * apContext) +void InvokeResponseIBWithCommandDataIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; - CommandList::Builder commandListBuilder; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - commandListBuilder.Init(&writer); - BuildCommandList(apSuite, commandListBuilder); + invokeResponseIBBuilder.Init(&writer); + BuildInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1505,16 +1629,21 @@ void CommandListTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseCommandList(apSuite, reader); + + invokeResponseIBParser.Init(reader); + ParseInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBParser); } -void ReportDataMessageTest(nlTestSuite * apSuite, void * apContext) +void InvokeResponseIBWithCommandStatusIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - BuildReportDataMessage(apSuite, writer); + invokeResponseIBBuilder.Init(&writer); + BuildInvokeResponseIBWithCommandStatusIB(apSuite, invokeResponseIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1524,16 +1653,84 @@ void ReportDataMessageTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseReportDataMessage(apSuite, reader); + + invokeResponseIBParser.Init(reader); + ParseInvokeResponseIBWithCommandStatusIB(apSuite, invokeResponseIBParser); +} + +void InvokeResponseIBWithMalformDataTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + invokeResponseIBBuilder.Init(&writer); + BuildWrongInvokeResponseIB(apSuite, invokeResponseIBBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + invokeResponseIBParser.Init(reader); + ParseWrongInvokeResponseIB(apSuite, invokeResponseIBParser); +} + +void InvokeRequestsTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + InvokeRequests::Builder invokeRequestsBuilder; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + invokeRequestsBuilder.Init(&writer); + BuildInvokeRequests(apSuite, invokeRequestsBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeRequests(apSuite, reader); +} + +void InvokeResponsesTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + InvokeResponses::Builder invokeResponsesBuilder; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + invokeResponsesBuilder.Init(&writer); + BuildInvokeResponses(apSuite, invokeResponsesBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeResponses(apSuite, reader); } -void InvokeCommandTest(nlTestSuite * apSuite, void * apContext) +void InvokeInvokeRequestMessageTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - BuildInvokeCommand(apSuite, writer); + BuildInvokeRequestMessage(apSuite, writer); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1543,7 +1740,45 @@ void InvokeCommandTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseInvokeCommand(apSuite, reader); + ParseInvokeRequestMessage(apSuite, reader); +} + +void InvokeInvokeResponseMessageTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + BuildInvokeResponseMessage(apSuite, writer); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeResponseMessage(apSuite, reader); +} + +void ReportDataMessageTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + BuildReportDataMessage(apSuite, writer); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseReportDataMessage(apSuite, reader); } void ReadRequestMessageTest(nlTestSuite * apSuite, void * apContext) @@ -1726,7 +1961,6 @@ const nlTest sTests[] = NL_TEST_DEF("AttributePathListTest", AttributePathListTest), NL_TEST_DEF("EventPathTest", EventPathTest), NL_TEST_DEF("EventPathsTest", EventPathsTest), - NL_TEST_DEF("CommandPathTest", CommandPathTest), NL_TEST_DEF("EventDataElementTest", EventDataElementTest), NL_TEST_DEF("EventListTest", EventListTest), NL_TEST_DEF("StatusIBTest", StatusIBTest), @@ -1735,11 +1969,17 @@ const nlTest sTests[] = NL_TEST_DEF("AttributeDataElementTest", AttributeDataElementTest), NL_TEST_DEF("AttributeDataListTest", AttributeDataListTest), NL_TEST_DEF("AttributeDataVersionListTest", AttributeDataVersionListTest), + NL_TEST_DEF("CommandPathIBTest", CommandPathIBTest), NL_TEST_DEF("CommandDataIBTest", CommandDataIBTest), - NL_TEST_DEF("CommandDataIBWithStatusCodeTest", CommandDataIBWithStatusCodeTest), - NL_TEST_DEF("CommandListTest", CommandListTest), + NL_TEST_DEF("CommandStatusIBTest", CommandStatusIBTest), + NL_TEST_DEF("InvokeResponseIBWithCommandDataIBTest", InvokeResponseIBWithCommandDataIBTest), + NL_TEST_DEF("InvokeResponseIBWithCommandStatusIBTest", InvokeResponseIBWithCommandStatusIBTest), + NL_TEST_DEF("InvokeResponseIBWithMalformDataTest", InvokeResponseIBWithMalformDataTest), + NL_TEST_DEF("InvokeRequestsTest", InvokeRequestsTest), + NL_TEST_DEF("InvokeResponsesTest", InvokeResponsesTest), + NL_TEST_DEF("InvokeInvokeRequestMessageTest", InvokeInvokeRequestMessageTest), + NL_TEST_DEF("InvokeInvokeResponseMessageTest", InvokeInvokeResponseMessageTest), NL_TEST_DEF("ReportDataMessageTest", ReportDataMessageTest), - NL_TEST_DEF("InvokeCommandTest", InvokeCommandTest), NL_TEST_DEF("ReadRequestMessageTest", ReadRequestMessageTest), NL_TEST_DEF("WriteRequestMessageTest", WriteRequestMessageTest), NL_TEST_DEF("WriteResponseMessageTest", WriteResponseMessageTest), diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index 55b2452efdb743..172720afceaddf 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -605,7 +605,6 @@ void SubscribeRequestTimerHandler(chip::System::Layer * systemLayer, void * appS namespace chip { namespace app { - bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) { // Always return true in test. diff --git a/src/lib/core/CHIPError.cpp b/src/lib/core/CHIPError.cpp index 6ac83ca3b511e7..27e811faaad9d1 100644 --- a/src/lib/core/CHIPError.cpp +++ b/src/lib/core/CHIPError.cpp @@ -653,6 +653,18 @@ bool FormatCHIPError(char * buf, uint16_t bufSize, CHIP_ERROR err) case CHIP_ERROR_IM_STATUS_CODE_RECEIVED.AsInteger(): desc = "Interaction Model Error"; break; + case CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB.AsInteger(): + desc = "Malformed Interaction Model Command Status IB"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB.AsInteger(): + desc = "Malformed Interaction Model Invoke Response code IB"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE.AsInteger(): + desc = "Malformed Interaction Model Invoke Response Message"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE.AsInteger(): + desc = "Malformed Interaction Model Invoke Response MESSAGE"; + break; } #endif // !CHIP_CONFIG_SHORT_ERROR_STR diff --git a/src/lib/core/CHIPError.h b/src/lib/core/CHIPError.h index 2003bb0418ce2d..3fe6730b7472ab 100644 --- a/src/lib/core/CHIPError.h +++ b/src/lib/core/CHIPError.h @@ -2216,6 +2216,42 @@ using CHIP_ERROR = ::chip::ChipError; */ #define CHIP_ERROR_ANOTHER_COMMISSIONING_IN_PROGRESS CHIP_CORE_ERROR(0xcb) +/** + * @def CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB + * + * @brief + * The CommandStatusCodeIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB CHIP_CORE_ERROR(0xcb) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB + * + * @brief + * The InvokeResponseIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB CHIP_CORE_ERROR(0xcc) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE + * + * @brief + * The InvokeResponseMessage is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE CHIP_CORE_ERROR(0xcd) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE + * + * @brief + * The InvokeResponseMessage is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE CHIP_CORE_ERROR(0xce) + /** * @} */