Skip to content

Commit

Permalink
Add IM status response support
Browse files Browse the repository at this point in the history
Problems:
Interaction Model spec has introduced status reponse message and used it
for IM Read/Subscribe. Currently IM read/subscribe code still use status
report from secure channel, we need to update it with status reponse.

Summary of Changes:
-- Add status reponse message builder and parser and test
-- Replace status report with status response message for IM
read/subscribe
-- Move protocol code type from uint16_t to uint32_t. For status code
change in other IM message, we will do it in another PR.
  • Loading branch information
yunhanw-google committed Sep 14, 2021
1 parent e71f2d7 commit 8f3bc0e
Show file tree
Hide file tree
Showing 23 changed files with 406 additions and 56 deletions.
1 change: 1 addition & 0 deletions src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static_library("app") {
"MessageDef/ReportData.h",
"MessageDef/StatusElement.cpp",
"MessageDef/StatusElement.h",
"MessageDef/StatusResponse.cpp",
"MessageDef/SubscribeRequest.cpp",
"MessageDef/SubscribeResponse.cpp",
"MessageDef/TimedRequest.cpp",
Expand Down
2 changes: 1 addition & 1 deletion src/app/CommandSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ CHIP_ERROR CommandSender::ProcessCommandDataElement(CommandDataElement::Parser &
chip::EndpointId endpointId;
Protocols::SecureChannel::GeneralStatusCode generalCode = Protocols::SecureChannel::GeneralStatusCode::kSuccess;
uint32_t protocolId = 0;
uint16_t protocolCode = 0;
uint32_t protocolCode = 0;
StatusElement::Parser statusElementParser;

mCommandIndex++;
Expand Down
4 changes: 2 additions & 2 deletions src/app/InteractionModelDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class InteractionModelDelegate
*/
virtual CHIP_ERROR CommandResponseStatus(const CommandSender * apCommandSender,
const Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
const uint32_t aProtocolId, const uint16_t aProtocolCode, EndpointId aEndpointId,
const uint32_t aProtocolId, const uint32_t aProtocolCode, EndpointId aEndpointId,
const ClusterId aClusterId, CommandId aCommandId, uint8_t aCommandIndex)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
Expand Down Expand Up @@ -163,7 +163,7 @@ class InteractionModelDelegate
*/
virtual CHIP_ERROR WriteResponseStatus(const WriteClient * apWriteClient,
const Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
const uint32_t aProtocolId, const uint16_t aProtocolCode,
const uint32_t aProtocolId, const uint32_t aProtocolCode,
AttributePathParams & aAttributePathParams, uint8_t aAttributeIndex)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
Expand Down
2 changes: 1 addition & 1 deletion src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ CHIP_ERROR InteractionModelEngine::OnUnknownMsgType(Messaging::ExchangeContext *
ChipLogDetail(InteractionModel, "Msg type %d not supported", aPayloadHeader.GetMessageType());

// Todo: Add status report
// err = SendStatusReport(ec, kChipProfile_Common, kStatus_UnsupportedMessage);
// err = SendStatusResponse(ec, kChipProfile_Common, kStatus_UnsupportedMessage);
// SuccessOrExit(err);

apExchangeContext = nullptr;
Expand Down
4 changes: 2 additions & 2 deletions src/app/MessageDef/StatusElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ CHIP_ERROR StatusElement::Parser::Init(const chip::TLV::TLVReader & aReader)
}

CHIP_ERROR StatusElement::Parser::DecodeStatusElement(Protocols::SecureChannel::GeneralStatusCode * apGeneralCode,
uint32_t * apProtocolId, uint16_t * apProtocolCode) const
uint32_t * apProtocolId, uint32_t * apProtocolCode) const
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::TLV::TLVReader lReader;
Expand Down Expand Up @@ -188,7 +188,7 @@ CHIP_ERROR StatusElement::Builder::Init(chip::TLV::TLVWriter * const apWriter, c
}

StatusElement::Builder & StatusElement::Builder::EncodeStatusElement(const Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
const uint32_t aProtocolId, const uint16_t aProtocolCode)
const uint32_t aProtocolId, const uint32_t aProtocolCode)
{
uint64_t tag = chip::TLV::AnonymousTag;

Expand Down
4 changes: 2 additions & 2 deletions src/app/MessageDef/StatusElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Parser : public ListParser
* type.
*/
CHIP_ERROR DecodeStatusElement(Protocols::SecureChannel::GeneralStatusCode * apGeneralCode, uint32_t * apProtocolId,
uint16_t * apProtocolCode) const;
uint32_t * apProtocolCode) const;
};

class Builder : public ListBuilder
Expand Down Expand Up @@ -124,7 +124,7 @@ class Builder : public ListBuilder
* type.
*/
StatusElement::Builder & EncodeStatusElement(const Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
const uint32_t aProtocolId, const uint16_t aProtocolCode);
const uint32_t aProtocolId, const uint32_t aProtocolCode);

/**
* @brief Mark the end of this StatusElement
Expand Down
103 changes: 103 additions & 0 deletions src/app/MessageDef/StatusResponse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
*
* 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 <app/MessageDef/MessageDefHelper.h>
#include <app/MessageDef/StatusResponse.h>

namespace chip {
namespace app {
CHIP_ERROR StatusResponse::Parser::Init(const TLV::TLVReader & aReader)
{
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrReturnLogError(TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
ReturnLogErrorOnFailure(mReader.EnterContainer(mOuterContainerType));
return CHIP_NO_ERROR;
}

#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
CHIP_ERROR StatusResponse::Parser::CheckSchemaValidity() const
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint16_t TagPresenceMask = 0;
TLV::TLVReader reader;
PRETTY_PRINT("StatusResponse =");
PRETTY_PRINT("{");

// make a copy of the reader
reader.Init(mReader);

while (CHIP_NO_ERROR == (err = reader.Next()))
{
VerifyOrReturnLogError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG);
switch (TLV::TagNumFromTag(reader.GetTag()))
{
case kCsTag_Status:
VerifyOrReturnLogError(!(TagPresenceMask & (1 << kCsTag_Status)), CHIP_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_Status);
VerifyOrReturnLogError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
#if CHIP_DETAIL_LOGGING
{
uint32_t status;
ReturnLogErrorOnFailure(reader.Get(status));
PRETTY_PRINT("\tStatus = 0x%" PRIx32 ",", status);
}
#endif // CHIP_DETAIL_LOGGING
break;
default:
ReturnLogErrorOnFailure(CHIP_ERROR_INVALID_TLV_TAG);
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");

if (CHIP_END_OF_TLV == err)
{
const uint16_t RequiredFields = (1 << kCsTag_Status);

if ((TagPresenceMask & RequiredFields) == RequiredFields)
{
err = CHIP_NO_ERROR;
}
}
ReturnLogErrorOnFailure(err);
return reader.ExitContainer(mOuterContainerType);
}
#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK

CHIP_ERROR StatusResponse::Parser::GetStatus(uint32_t * const apStatus) const
{
return GetUnsignedInteger(kCsTag_Status, apStatus);
}

CHIP_ERROR StatusResponse::Builder::Init(TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}

StatusResponse::Builder & StatusResponse::Builder::Status(const uint32_t aStatus)
{
// skip if error has already been set
if (mError == CHIP_NO_ERROR)
{
mError = mpWriter->Put(TLV::ContextTag(kCsTag_Status), aStatus);
}
EndOfContainer();
return *this;
}

} // namespace app
} // namespace chip
77 changes: 77 additions & 0 deletions src/app/MessageDef/StatusResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
*
* 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 "Builder.h"
#include "Parser.h"
#include <app/AppBuildConfig.h>
#include <app/util/basic-types.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPTLV.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>

namespace chip {
namespace app {
namespace StatusResponse {
enum
{
kCsTag_Status = 0,
};

class Parser : public app::Parser
{
public:
/**
* @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this response
*/
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 Status. 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 GetStatus(uint32_t * const apStatus) const;
};

class Builder : public app::Builder
{
public:
CHIP_ERROR Init(TLV::TLVWriter * const apWriter);
StatusResponse::Builder & Status(const uint32_t aStatus);
};
} // namespace StatusResponse
} // namespace app
} // namespace chip
33 changes: 16 additions & 17 deletions src/app/ReadClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <app/AppBuildConfig.h>
#include <app/InteractionModelEngine.h>
#include <app/ReadClient.h>
#include <protocols/secure_channel/StatusReport.h>

namespace chip {
namespace app {
Expand Down Expand Up @@ -189,25 +188,25 @@ CHIP_ERROR ReadClient::SendReadRequest(ReadPrepareParams & aReadPrepareParams)
return err;
}

CHIP_ERROR ReadClient::SendStatusReport(CHIP_ERROR aError)
CHIP_ERROR ReadClient::SendStatusResponse(CHIP_ERROR aError)
{
Protocols::SecureChannel::GeneralStatusCode generalCode = Protocols::SecureChannel::GeneralStatusCode::kSuccess;
uint32_t protocolId = Protocols::InteractionModel::Id.ToFullyQualifiedSpecForm();
uint16_t protocolCode = to_underlying(Protocols::InteractionModel::ProtocolCode::Success);
VerifyOrReturnLogError(mpExchangeCtx != nullptr, CHIP_ERROR_INCORRECT_STATE);
System::PacketBufferHandle msgBuf = System::PacketBufferHandle::New(kMaxSecureSduLengthBytes);
VerifyOrReturnLogError(!msgBuf.IsNull(), CHIP_ERROR_NO_MEMORY);

System::PacketBufferTLVWriter writer;
writer.Init(std::move(msgBuf));

StatusResponse::Builder response;
ReturnLogErrorOnFailure(response.Init(&writer));
uint32_t statusCode = to_underlying(Protocols::InteractionModel::ProtocolCode::Success);
if (aError != CHIP_NO_ERROR)
{
generalCode = Protocols::SecureChannel::GeneralStatusCode::kFailure;
protocolCode = to_underlying(Protocols::InteractionModel::ProtocolCode::InvalidSubscription);
statusCode = to_underlying(Protocols::InteractionModel::ProtocolCode::InvalidSubscription);
}

Protocols::SecureChannel::StatusReport report(generalCode, protocolId, protocolCode);

Encoding::LittleEndian::PacketBufferWriter buf(System::PacketBufferHandle::New(kMaxSecureSduLengthBytes));
report.WriteToBuffer(buf);
System::PacketBufferHandle msgBuf = buf.Finalize();
VerifyOrReturnLogError(!msgBuf.IsNull(), CHIP_ERROR_NO_MEMORY);
response.Status(statusCode);
ReturnLogErrorOnFailure(response.GetError());
ReturnLogErrorOnFailure(writer.Finalize(&msgBuf));
VerifyOrReturnLogError(mpExchangeCtx != nullptr, CHIP_ERROR_INCORRECT_STATE);

if (IsSubscriptionType())
{
Expand All @@ -221,7 +220,7 @@ CHIP_ERROR ReadClient::SendStatusReport(CHIP_ERROR aError)
}
}
ReturnLogErrorOnFailure(
mpExchangeCtx->SendMessage(Protocols::SecureChannel::MsgType::StatusReport, std::move(msgBuf),
mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::StatusResponse, std::move(msgBuf),
Messaging::SendFlags(IsAwaitingSubscribeResponse() ? Messaging::SendMessageFlags::kExpectResponse
: Messaging::SendMessageFlags::kNone)));
return CHIP_NO_ERROR;
Expand Down Expand Up @@ -439,7 +438,7 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle && aPayload)
mpDelegate->ReportProcessed(this);
}
exit:
SendStatusReport(err);
SendStatusResponse(err);
if (!mInitialReport)
{
mpExchangeCtx = nullptr;
Expand Down
3 changes: 2 additions & 1 deletion src/app/ReadClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <app/EventPathParams.h>
#include <app/InteractionModelDelegate.h>
#include <app/MessageDef/ReadRequest.h>
#include <app/MessageDef/StatusResponse.h>
#include <app/MessageDef/SubscribeRequest.h>
#include <app/MessageDef/SubscribeResponse.h>
#include <app/ReadPrepareParams.h>
Expand Down Expand Up @@ -95,7 +96,7 @@ class ReadClient : public Messaging::ExchangeDelegate
Messaging::ExchangeContext * GetExchangeContext() const { return mpExchangeCtx; }
bool IsReadType() { return mInteractionType == InteractionType::Read; }
bool IsSubscriptionType() const { return mInteractionType == InteractionType::Subscribe; };
CHIP_ERROR SendStatusReport(CHIP_ERROR aError);
CHIP_ERROR SendStatusResponse(CHIP_ERROR aError);

private:
friend class TestReadInteraction;
Expand Down
Loading

0 comments on commit 8f3bc0e

Please sign in to comment.