Line data Source code
1 : /* 2 : * Copyright (c) 2024 Project CHIP Authors 3 : * All rights reserved. 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #pragma once 19 : 20 : #include <app/StatusResponse.h> 21 : #include <messaging/ExchangeHolder.h> 22 : #include <system/SystemPacketBuffer.h> 23 : 24 : namespace chip { 25 : namespace app { 26 : 27 : typedef void (*OnResponseSenderDone)(void * context); 28 : class CommandHandler; 29 : 30 : /** 31 : * Class manages the process of sending `InvokeResponseMessage`(s) back to the initial requester. 32 : */ 33 : class CommandResponseSender : public Messaging::ExchangeDelegate 34 : { 35 : public: 36 49 : CommandResponseSender() : mExchangeCtx(*this) {} 37 : 38 : CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader, 39 : System::PacketBufferHandle && payload) override; 40 : 41 : void OnResponseTimeout(Messaging::ExchangeContext * ec) override; 42 : 43 : /** 44 : * Gets the inner exchange context object, without ownership. 45 : * 46 : * WARNING: This is dangerous, since it is directly interacting with the 47 : * exchange being managed automatically by mExchangeCtx and 48 : * if not done carefully, may end up with use-after-free errors. 49 : * 50 : * @return The inner exchange context, might be nullptr if no 51 : * exchange context has been assigned or the context 52 : * has been released. 53 : */ 54 : Messaging::ExchangeContext * GetExchangeContext() const { return mExchangeCtx.Get(); } 55 : 56 : /** 57 : * @brief Flush acks right now, typically done when processing a slow command 58 : */ 59 : void FlushAcksRightNow() 60 : { 61 : VerifyOrReturn(mExchangeCtx); 62 : auto * msgContext = mExchangeCtx->GetReliableMessageContext(); 63 : VerifyOrReturn(msgContext != nullptr); 64 : msgContext->FlushAcks(); 65 : } 66 : 67 : /** 68 : * Gets subject descriptor of the exchange. 69 : * 70 : * WARNING: This method should only be called when the caller is certain the 71 : * session has not been evicted. 72 : */ 73 81 : Access::SubjectDescriptor GetSubjectDescriptor() const 74 : { 75 81 : VerifyOrDie(mExchangeCtx); 76 81 : return mExchangeCtx->GetSessionHandle()->GetSubjectDescriptor(); 77 : } 78 : 79 27 : bool HasSessionHandle() { return mExchangeCtx && mExchangeCtx->HasSessionHandle(); } 80 : 81 0 : FabricIndex GetAccessingFabricIndex() const 82 : { 83 0 : VerifyOrDie(mExchangeCtx); 84 0 : return mExchangeCtx->GetSessionHandle()->GetFabricIndex(); 85 : } 86 : 87 15 : void SetExchangeContext(Messaging::ExchangeContext * ec) { mExchangeCtx.Grab(ec); } 88 : 89 31 : void WillSendMessage() { mExchangeCtx->WillSendMessage(); } 90 : 91 38 : bool IsForGroup() 92 : { 93 38 : VerifyOrDie(mExchangeCtx); 94 38 : return mExchangeCtx->IsGroupExchangeContext(); 95 : } 96 : 97 56 : bool HasExchangeContext() { return mExchangeCtx.Get() != nullptr; } 98 : 99 0 : GroupId GetGroupId() 100 : { 101 0 : VerifyOrDie(mExchangeCtx); 102 0 : return mExchangeCtx->GetSessionHandle()->AsIncomingGroupSession()->GetGroupId(); 103 : } 104 : 105 : /** 106 : * @brief Initiates the sending of InvokeResponses previously queued using AddInvokeResponseToSend. 107 : * 108 : * Upon failure, the caller is responsible for closing the exchange appropriately, potentially 109 : * by calling `SendStatusResponse`. 110 : */ 111 : CHIP_ERROR StartSendingCommandResponses(); 112 : 113 3 : void SendStatusResponse(Protocols::InteractionModel::Status aStatus) 114 : { 115 3 : StatusResponse::Send(aStatus, mExchangeCtx.Get(), /*aExpectResponse = */ false); 116 3 : } 117 : 118 31 : bool AwaitingStatusResponse() { return mState == State::AwaitingStatusResponse; } 119 : 120 38 : void AddInvokeResponseToSend(System::PacketBufferHandle && aPacket) 121 : { 122 38 : VerifyOrDie(mState == State::ReadyForInvokeResponses); 123 38 : mChunks.AddToEnd(std::move(aPacket)); 124 38 : } 125 : 126 : /** 127 : * @brief Called to indicate that response was dropped 128 : */ 129 0 : void ResponseDropped() { mReportResponseDropped = true; } 130 : 131 : /** 132 : * @brief Registers a callback to be invoked when CommandResponseSender has finished sending responses. 133 : */ 134 0 : void RegisterOnResponseSenderDoneCallback(Callback::Callback<OnResponseSenderDone> * aResponseSenderDoneCallback) 135 : { 136 0 : VerifyOrDie(!mCloseCalled); 137 0 : mResponseSenderDoneCallback = aResponseSenderDoneCallback; 138 0 : } 139 : 140 : private: 141 : enum class State : uint8_t 142 : { 143 : ReadyForInvokeResponses, ///< Accepting InvokeResponses to send back to requester. 144 : AwaitingStatusResponse, ///< Awaiting status response from requester, after sending InvokeResponse. 145 : AllInvokeResponsesSent, ///< All InvokeResponses have been sent out. 146 : }; 147 : 148 : void MoveToState(const State aTargetState); 149 : const char * GetStateStr() const; 150 : 151 : CHIP_ERROR SendCommandResponse(); 152 83 : bool HasMoreToSend() { return !mChunks.IsNull() || mReportResponseDropped; } 153 : void Close(); 154 : 155 : // A list of InvokeResponseMessages to be sent out by CommandResponseSender. 156 : System::PacketBufferHandle mChunks; 157 : 158 : chip::Callback::Callback<OnResponseSenderDone> * mResponseSenderDoneCallback = nullptr; 159 : Messaging::ExchangeHolder mExchangeCtx; 160 : State mState = State::ReadyForInvokeResponses; 161 : 162 : bool mCloseCalled = false; 163 : bool mReportResponseDropped = false; 164 : }; 165 : 166 : } // namespace app 167 : } // namespace chip