Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add IM status response support and replace status report with status response for IM read/subscribe #9706

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
101 changes: 101 additions & 0 deletions src/app/MessageDef/StatusResponse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
*
* 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 "StatusResponse.h"
#include "MessageDefHelper.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;
bool statusTagPresence = false;
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(!statusTagPresence, CHIP_ERROR_INVALID_TLV_TAG);
statusTagPresence = true;
VerifyOrReturnLogError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
#if CHIP_DETAIL_LOGGING
{
uint16_t status;
ReturnLogErrorOnFailure(reader.Get(status));
PRETTY_PRINT("\tStatus = 0x%" PRIx16 ",", status);
}
#endif // CHIP_DETAIL_LOGGING
break;
default:
ReturnLogErrorOnFailure(CHIP_ERROR_INVALID_TLV_TAG);
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");

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

CHIP_ERROR StatusResponse::Parser::GetStatus(Protocols::InteractionModel::ProtocolCode & aStatus) const
{
uint16_t status = 0;
CHIP_ERROR err = GetUnsignedInteger(kCsTag_Status, &status);
aStatus = static_cast<Protocols::InteractionModel::ProtocolCode>(status);
return err;
}

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

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

} // namespace app
} // namespace chip
78 changes: 78 additions & 0 deletions src/app/MessageDef/StatusResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
*
* 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>
#include <protocols/interaction_model/Constants.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(Protocols::InteractionModel::ProtocolCode & aStatus) const;
};

class Builder : public app::Builder
{
public:
CHIP_ERROR Init(TLV::TLVWriter * const apWriter);
StatusResponse::Builder & Status(const Protocols::InteractionModel::ProtocolCode 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)
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
{
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));
Protocols::InteractionModel::ProtocolCode statusCode = Protocols::InteractionModel::ProtocolCode::Success;
if (aError != CHIP_NO_ERROR)
{
generalCode = Protocols::SecureChannel::GeneralStatusCode::kFailure;
protocolCode = to_underlying(Protocols::InteractionModel::ProtocolCode::InvalidSubscription);
statusCode = 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
35 changes: 23 additions & 12 deletions src/app/ReadHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
#include <app/AppBuildConfig.h>
#include <app/InteractionModelEngine.h>
#include <app/MessageDef/EventPath.h>
#include <app/MessageDef/StatusResponse.h>
#include <app/MessageDef/SubscribeRequest.h>
#include <app/MessageDef/SubscribeResponse.h>
#include <app/ReadHandler.h>
#include <app/reporting/Engine.h>
#include <lib/support/RandUtils.h>
#include <protocols/secure_channel/StatusReport.h>

namespace chip {
namespace app {
Expand Down Expand Up @@ -120,17 +120,28 @@ CHIP_ERROR ReadHandler::OnReadInitialRequest(System::PacketBufferHandle && aPayl
return err;
}

CHIP_ERROR ReadHandler::OnStatusReport(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Protocols::SecureChannel::StatusReport statusReport;
err = statusReport.Parse(std::move(aPayload));
Protocols::InteractionModel::ProtocolCode statusCode;
StatusResponse::Parser response;
System::PacketBufferTLVReader reader;
reader.Init(std::move(aPayload));
reader.Next();
err = response.Init(reader);
SuccessOrExit(err);

#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
err = response.CheckSchemaValidity();
SuccessOrExit(err);
ChipLogProgress(DataManagement, "in state %s, receive status report, protocol id is %" PRIu32 ", protocol code is %" PRIu16,
GetStateStr(), statusReport.GetProtocolId(), statusReport.GetProtocolCode());
VerifyOrExit((statusReport.GetProtocolId() == Protocols::InteractionModel::Id.ToFullyQualifiedSpecForm()) &&
(statusReport.GetProtocolCode() == to_underlying(Protocols::InteractionModel::ProtocolCode::Success)),
err = CHIP_ERROR_INVALID_ARGUMENT);
#endif

err = response.GetStatus(statusCode);
SuccessOrExit(err);

ChipLogProgress(DataManagement, "In state %s, receive status response, status code is %" PRIu16, GetStateStr(),
to_underlying(statusCode));
VerifyOrExit((statusCode == Protocols::InteractionModel::ProtocolCode::Success), err = CHIP_ERROR_INVALID_ARGUMENT);
switch (mState)
{
case HandlerState::AwaitingReportResponse:
Expand Down Expand Up @@ -201,9 +212,9 @@ CHIP_ERROR ReadHandler::OnMessageReceived(Messaging::ExchangeContext * apExchang
{
CHIP_ERROR err = CHIP_NO_ERROR;

if (aPayloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
{
err = OnStatusReport(apExchangeContext, std::move(aPayload));
err = OnStatusResponse(apExchangeContext, std::move(aPayload));
}
else
{
Expand Down Expand Up @@ -477,7 +488,7 @@ CHIP_ERROR ReadHandler::SendSubscribeResponse()
SubscribeResponse::Builder response;
ReturnLogErrorOnFailure(response.Init(&writer));
response.SubscriptionId(mSubscriptionId)
.MinIntervalFloorSeconds(mMaxIntervalCeilingSeconds)
.MinIntervalFloorSeconds(mMinIntervalFloorSeconds)
.MaxIntervalCeilingSeconds(mMaxIntervalCeilingSeconds)
.EndOfSubscribeResponse();
ReturnLogErrorOnFailure(response.GetError());
Expand Down
2 changes: 1 addition & 1 deletion src/app/ReadHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class ReadHandler : public Messaging::ExchangeDelegate
CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle && aPayload);
CHIP_ERROR ProcessAttributePathList(AttributePathList::Parser & aAttributePathListParser);
CHIP_ERROR ProcessEventPathList(EventPathList::Parser & aEventPathListParser);
CHIP_ERROR OnStatusReport(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
CHIP_ERROR OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
System::PacketBufferHandle && aPayload) override;
void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
Expand Down
1 change: 1 addition & 0 deletions src/app/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ chip_test_suite("tests") {
"TestMessageDef.cpp",
"TestReadInteraction.cpp",
"TestReportingEngine.cpp",
"TestStatusResponse.cpp",
"TestWriteInteraction.cpp",
]

Expand Down
Loading