Skip to content

Commit

Permalink
Close exchanges automatically after a message send if no response is …
Browse files Browse the repository at this point in the history
…expected (project-chip#8459)
  • Loading branch information
bzbarsky-apple authored Jul 27, 2021
1 parent 5d91959 commit 5da31a9
Show file tree
Hide file tree
Showing 21 changed files with 98 additions and 130 deletions.
33 changes: 9 additions & 24 deletions examples/shell/shell_common/cmd_send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ using namespace Logging;

namespace {

Messaging::ExchangeContext * gExchangeCtx = nullptr;

class SendArguments
{
public:
Expand Down Expand Up @@ -110,16 +108,13 @@ class MockAppDelegate : public Messaging::ExchangeDelegate
streamer_printf(sout, "Response received: len=%u time=%.3fms\n", buffer->DataLength(),
static_cast<double>(transitTime) / 1000);

gExchangeCtx = nullptr;
return CHIP_NO_ERROR;
}

void OnResponseTimeout(Messaging::ExchangeContext * ec) override
{
streamer_t * sout = streamer_get();
streamer_printf(sout, "No response received\n");

gExchangeCtx = nullptr;
}
} gMockAppDelegate;

Expand All @@ -131,17 +126,9 @@ CHIP_ERROR SendMessage(streamer_t * stream)
System::PacketBufferHandle payloadBuf;
uint32_t payloadSize = gSendArguments.GetPayloadSize();

// Discard any existing exchange context. Effectively we can only have one exchange with
// a single node at any one time.
if (gExchangeCtx != nullptr)
{
gExchangeCtx->Abort();
gExchangeCtx = nullptr;
}

// Create a new exchange context.
gExchangeCtx = gExchangeManager.NewContext({ kTestDeviceNodeId, 0, gFabricIndex }, &gMockAppDelegate);
VerifyOrExit(gExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
auto * ec = gExchangeManager.NewContext({ kTestDeviceNodeId, 0, gFabricIndex }, &gMockAppDelegate);
VerifyOrExit(ec != nullptr, err = CHIP_ERROR_NO_MEMORY);

payloadBuf = MessagePacketBuffer::New(payloadSize);
VerifyOrExit(!payloadBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
Expand All @@ -158,26 +145,24 @@ CHIP_ERROR SendMessage(streamer_t * stream)
sendFlags.Set(Messaging::SendMessageFlags::kNoAutoRequestAck);
}

gExchangeCtx->SetResponseTimeout(kResponseTimeOut);
ec->SetResponseTimeout(kResponseTimeOut);
sendFlags.Set(Messaging::SendMessageFlags::kExpectResponse);

gSendArguments.SetLastSendTime(System::Clock::GetMonotonicMilliseconds());

streamer_printf(stream, "\nSend CHIP message with payload size: %d bytes to Node: %" PRIu64 "\n", payloadSize,
kTestDeviceNodeId);

err = gExchangeCtx->SendMessage(Protocols::Id(VendorId::Common, gSendArguments.GetProtocolId()),
gSendArguments.GetMessageType(), std::move(payloadBuf), sendFlags);

if (err != CHIP_NO_ERROR)
{
gExchangeCtx->Abort();
gExchangeCtx = nullptr;
}
err = ec->SendMessage(Protocols::Id(VendorId::Common, gSendArguments.GetProtocolId()), gSendArguments.GetMessageType(),
std::move(payloadBuf), sendFlags);

exit:
if (err != CHIP_NO_ERROR)
{
if (ec != nullptr)
{
ec->Close();
}
streamer_printf(stream, "Send CHIP message failed, err: %s\n", ErrorStr(err));
}

Expand Down
23 changes: 7 additions & 16 deletions src/app/ReadHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ CHIP_ERROR ReadHandler::Init(InteractionModelDelegate * apDelegate)
// Error if already initialized.
VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
mpExchangeCtx = nullptr;
mpDelegate = apDelegate;
mSuppressResponse = true;
mpAttributeClusterInfoList = nullptr;
mpEventClusterInfoList = nullptr;
Expand All @@ -52,25 +51,13 @@ void ReadHandler::Shutdown()
{
InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(mpAttributeClusterInfoList);
InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(mpEventClusterInfoList);
AbortExistingExchangeContext();
mpExchangeCtx = nullptr;
MoveToState(HandlerState::Uninitialized);
mpDelegate = nullptr;
mpAttributeClusterInfoList = nullptr;
mpEventClusterInfoList = nullptr;
mCurrentPriority = PriorityLevel::Invalid;
}

CHIP_ERROR ReadHandler::AbortExistingExchangeContext()
{
if (mpExchangeCtx != nullptr)
{
mpExchangeCtx->Abort();
mpExchangeCtx = nullptr;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR ReadHandler::OnReadRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -82,8 +69,6 @@ CHIP_ERROR ReadHandler::OnReadRequest(Messaging::ExchangeContext * apExchangeCon
if (err != CHIP_NO_ERROR)
{
ChipLogFunctError(err);
// Keep Shutdown() from double-closing our exchange.
mpExchangeCtx = nullptr;
Shutdown();
}

Expand All @@ -96,6 +81,12 @@ CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload)
VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_INCORRECT_STATE);

err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload));

if (err != CHIP_NO_ERROR)
{
mpExchangeCtx->Close();
}

exit:
ChipLogFunctError(err);
Shutdown();
Expand Down
2 changes: 0 additions & 2 deletions src/app/ReadHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ class ReadHandler
void MoveToState(const HandlerState aTargetState);

const char * GetStateStr() const;
CHIP_ERROR AbortExistingExchangeContext();

Messaging::ExchangeContext * mpExchangeCtx = nullptr;
InteractionModelDelegate * mpDelegate = nullptr;

// Don't need the response for report data if true
bool mSuppressResponse = false;
Expand Down
16 changes: 1 addition & 15 deletions src/app/WriteHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ CHIP_ERROR WriteHandler::Init(InteractionModelDelegate * apDelegate)
{
VerifyOrReturnError(apDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(mpExchangeCtx == nullptr, CHIP_ERROR_INCORRECT_STATE);
mpExchangeCtx = nullptr;
mpDelegate = apDelegate;

System::PacketBufferHandle packet = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
VerifyOrReturnError(!packet.IsNull(), CHIP_ERROR_NO_MEMORY);
Expand All @@ -50,20 +48,10 @@ void WriteHandler::Shutdown()
{
VerifyOrReturn(mState != State::Uninitialized);
mMessageWriter.Reset();
ClearExistingExchangeContext();
mpDelegate = nullptr;
mpExchangeCtx = nullptr;
ClearState();
}

void WriteHandler::ClearExistingExchangeContext()
{
if (mpExchangeCtx != nullptr)
{
mpExchangeCtx->Close();
mpExchangeCtx = nullptr;
}
}

CHIP_ERROR WriteHandler::OnWriteRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -75,8 +63,6 @@ CHIP_ERROR WriteHandler::OnWriteRequest(Messaging::ExchangeContext * apExchangeC

exit:
ChipLogFunctError(err);
// Keep Shutdown() from double-closing our exchange.
mpExchangeCtx = nullptr;
Shutdown();
return err;
}
Expand Down
2 changes: 0 additions & 2 deletions src/app/WriteHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,8 @@ class WriteHandler
void MoveToState(const State aTargetState);
void ClearState();
const char * GetStateStr() const;
void ClearExistingExchangeContext();

Messaging::ExchangeContext * mpExchangeCtx = nullptr;
InteractionModelDelegate * mpDelegate = nullptr;
WriteResponse::Builder mWriteResponseBuilder;
System::PacketBufferTLVWriter mMessageWriter;
State mState = State::Uninitialized;
Expand Down
4 changes: 0 additions & 4 deletions src/app/tests/TestWriteInteraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,6 @@ void TestWriteInteraction::TestWriteHandler(nlTestSuite * apSuite, void * apCont
Messaging::ExchangeContext * exchange = ctx.NewExchangeToLocal(&delegate);
err = writeHandler.OnWriteRequest(exchange, std::move(buf));
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
// Manually close the exchange, because we're bypassing the normal "you
// received a message" flow for the exchange, so the automatic closing is
// not going to happen.
exchange->Close();

Messaging::ReliableMessageMgr * rm = ctx.GetExchangeManager().GetReliableMessageMgr();
NL_TEST_ASSERT(apSuite, rm->TestGetCountRetransTable() == 0);
Expand Down
8 changes: 6 additions & 2 deletions src/app/util/chip-message-send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ EmberStatus chipSendUnicast(NodeId destination, EmberApsFrame * apsFrame, uint16

EmberStatus err = chipSendUnicast(exchange, apsFrame, messageLength, message, sendFlags);

// Make sure we always close the temporary exchange we just created.
exchange->Close();
// Make sure we always close the temporary exchange we just created, unless
// we sent a message successfully.
if (err != EMBER_SUCCESS)
{
exchange->Close();
}

return err;
}
5 changes: 4 additions & 1 deletion src/channel/tests/TestChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,14 @@ void CheckExchangeChannels(nlTestSuite * inSuite, void * inContext)
ec1->SendMessage(0x0001, 0x0002, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize));
NL_TEST_ASSERT(inSuite, !mockUnsolicitedAppDelegate.IsOnMessageReceivedCalled);

// Need to sort out what this test should really be testing and how; sending
// two messages in a row on an exchange is not something that really
// happens.

// send a good packet
ec1->SendMessage(0x0001, 0x0001, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize));
NL_TEST_ASSERT(inSuite, mockUnsolicitedAppDelegate.IsOnMessageReceivedCalled);

ec1->Close();
channelHandle.Release();
#endif
}
Expand Down
8 changes: 7 additions & 1 deletion src/controller/CHIPCluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CHIP_ERROR ClusterBase::SendCommand(uint8_t seqNum, chip::System::PacketBufferHa
Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Messaging::SendFlags sendFlags;

VerifyOrExit(mDevice != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(!payload.IsNull(), err = CHIP_ERROR_INTERNAL);
Expand All @@ -61,7 +62,12 @@ CHIP_ERROR ClusterBase::SendCommand(uint8_t seqNum, chip::System::PacketBufferHa
mDevice->AddResponseHandler(seqNum, onSuccessCallback, onFailureCallback);
}

err = mDevice->SendMessage(Protocols::TempZCL::MsgType::TempZCLRequest, std::move(payload));
if (onSuccessCallback != nullptr || onFailureCallback != nullptr)
{
sendFlags.Set(Messaging::SendMessageFlags::kExpectResponse);
}

err = mDevice->SendMessage(Protocols::TempZCL::MsgType::TempZCLRequest, sendFlags, std::move(payload));
SuccessOrExit(err);

exit:
Expand Down
7 changes: 4 additions & 3 deletions src/controller/CHIPDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ using namespace chip::Callback;

namespace chip {
namespace Controller {
CHIP_ERROR Device::SendMessage(Protocols::Id protocolId, uint8_t msgType, System::PacketBufferHandle && buffer)
CHIP_ERROR Device::SendMessage(Protocols::Id protocolId, uint8_t msgType, Messaging::SendFlags sendFlags,
System::PacketBufferHandle && buffer)
{
System::PacketBufferHandle resend;
bool loadedSecureSession = false;
Messaging::SendFlags sendFlags;

VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);

Expand Down Expand Up @@ -372,7 +372,8 @@ CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption optio
System::PacketBufferHandle outBuffer;
ReturnErrorOnFailure(writer.Finalize(&outBuffer));

ReturnErrorOnFailure(SendMessage(Protocols::ServiceProvisioning::MsgType::ServiceProvisioningRequest, std::move(outBuffer)));
ReturnErrorOnFailure(SendMessage(Protocols::ServiceProvisioning::MsgType::ServiceProvisioningRequest,
Messaging::SendMessageFlags::kNone, std::move(outBuffer)));

setupPayload.version = 0;
setupPayload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kBLE);
Expand Down
10 changes: 7 additions & 3 deletions src/controller/CHIPDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeDelegate.h>
#include <messaging/ExchangeMgr.h>
#include <messaging/Flags.h>
#include <protocols/secure_channel/CASESession.h>
#include <protocols/secure_channel/PASESession.h>
#include <protocols/secure_channel/SessionIDAllocator.h>
Expand Down Expand Up @@ -124,19 +125,22 @@ class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEsta
*
* @param[in] protocolId The protocol identifier of the CHIP message to be sent.
* @param[in] msgType The message type of the message to be sent. Must be a valid message type for protocolId.
* @param [in] sendFlags SendMessageFlags::kExpectResponse or SendMessageFlags::kNone
* @param[in] message The message payload to be sent.
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR SendMessage(Protocols::Id protocolId, uint8_t msgType, System::PacketBufferHandle && message);
CHIP_ERROR SendMessage(Protocols::Id protocolId, uint8_t msgType, Messaging::SendFlags sendFlags,
System::PacketBufferHandle && message);

/**
* A strongly-message-typed version of SendMessage.
*/
template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
CHIP_ERROR SendMessage(MessageType msgType, System::PacketBufferHandle && message)
CHIP_ERROR SendMessage(MessageType msgType, Messaging::SendFlags sendFlags, System::PacketBufferHandle && message)
{
return SendMessage(Protocols::MessageTypeTraits<MessageType>::ProtocolId(), to_underlying(msgType), std::move(message));
return SendMessage(Protocols::MessageTypeTraits<MessageType>::ProtocolId(), to_underlying(msgType), sendFlags,
std::move(message));
}

CHIP_ERROR SendReadAttributeRequest(app::AttributePathParams aPath, Callback::Cancelable * onSuccessCallback,
Expand Down
4 changes: 3 additions & 1 deletion src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,9 @@ JNI_METHOD(void, sendMessage)(JNIEnv * env, jobject self, jlong handle, jlong de
}
else
{
err = chipDevice->SendMessage(Protocols::TempZCL::MsgType::TempZCLRequest, std::move(buffer));
// We don't install a response handler, so aren't waiting for a response
err = chipDevice->SendMessage(Protocols::TempZCL::MsgType::TempZCLRequest, Messaging::SendMessageFlags::kNone,
std::move(buffer));
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ void ExchangeContext::SetResponseTimeout(Timeout timeout)
CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgType, PacketBufferHandle && msgBuf,
const SendFlags & sendFlags)
{
if (protocolId != Protocols::SecureChannel::Id || msgType != to_underlying(Protocols::SecureChannel::MsgType::StandaloneAck))
bool isStandaloneAck =
(protocolId == Protocols::SecureChannel::Id) && msgType == to_underlying(Protocols::SecureChannel::MsgType::StandaloneAck);
if (!isStandaloneAck)
{
// If we were waiting for a message send, this is it. Standalone acks
// are not application-level sends, which is why we don't allow those to
Expand Down Expand Up @@ -148,6 +150,12 @@ CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgTyp
SetResponseExpected(false);
}

// Standalone acks are not application-level message sends.
if (err == CHIP_NO_ERROR && !isStandaloneAck)
{
MessageHandled();
}

return err;
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/messaging/ExchangeContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext, public Referen
/**
* Send a CHIP message on this exchange.
*
* If SendMessage returns success and the message was not expecting a
* response, the exchange will close itself before returning, unless the
* message being sent is a standalone ack. If SendMessage returns failure,
* the caller is responsible for deciding what to do (e.g. closing the
* exchange, trying to re-establish a secure session, etc).
*
* @param[in] protocolId The protocol identifier of the CHIP message to be sent.
*
* @param[in] msgType The message type of the corresponding protocol.
Expand Down Expand Up @@ -177,7 +183,7 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext, public Referen
void SetResponseTimeout(Timeout timeout);

private:
Timeout mResponseTimeout; // Maximum time to wait for response (in milliseconds); 0 disables response timeout.
Timeout mResponseTimeout = 0; // Maximum time to wait for response (in milliseconds); 0 disables response timeout.
ExchangeDelegate * mDelegate = nullptr;
ExchangeManager * mExchangeMgr = nullptr;
ExchangeACL * mExchangeACL = nullptr;
Expand Down
Loading

0 comments on commit 5da31a9

Please sign in to comment.