Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2021 Project CHIP Authors 4 : * All rights reserved. 5 : * 6 : * Licensed under the Apache License, Version 2.0 (the "License"); 7 : * you may not use this file except in compliance with the License. 8 : * You may obtain a copy of the License at 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 12 : * Unless required by applicable law or agreed to in writing, software 13 : * distributed under the License is distributed on an "AS IS" BASIS, 14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 : * See the License for the specific language governing permissions and 16 : * limitations under the License. 17 : */ 18 : 19 : #pragma once 20 : #include <app/AttributeAccessToken.h> 21 : #include <app/AttributePathParams.h> 22 : #include <app/MessageDef/WriteResponseMessage.h> 23 : #include <lib/core/CHIPCore.h> 24 : #include <lib/core/TLVDebug.h> 25 : #include <lib/support/CodeUtils.h> 26 : #include <lib/support/DLLUtil.h> 27 : #include <lib/support/logging/CHIPLogging.h> 28 : #include <messaging/ExchangeHolder.h> 29 : #include <messaging/ExchangeMgr.h> 30 : #include <messaging/Flags.h> 31 : #include <protocols/Protocols.h> 32 : #include <protocols/interaction_model/Constants.h> 33 : #include <system/SystemPacketBuffer.h> 34 : #include <system/TLVPacketBufferBackingStore.h> 35 : 36 : namespace chip { 37 : namespace app { 38 : /** 39 : * @brief The write handler is responsible for processing a write request and sending a write reply. 40 : */ 41 : class WriteHandler : public Messaging::ExchangeDelegate 42 : { 43 : public: 44 100 : WriteHandler() : mExchangeCtx(*this) {} 45 : 46 : /** 47 : * Initialize the WriteHandler. Within the lifetime 48 : * of this instance, this method is invoked once after object 49 : * construction until a call to Close is made to terminate the 50 : * instance. 51 : * 52 : * @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to 53 : * kState_NotInitialized. 54 : * @retval #CHIP_NO_ERROR On success. 55 : */ 56 : CHIP_ERROR Init(); 57 : 58 : /** 59 : * Process a write request. Parts of the processing may end up being asynchronous, but the WriteHandler 60 : * guarantees that it will call Close on itself when processing is done (including if OnWriteRequest 61 : * returns an error). 62 : * 63 : * @param[in] apExchangeContext A pointer to the ExchangeContext. 64 : * @param[in] aPayload A payload that has read request data 65 : * @param[in] aIsTimedWrite Whether write is part of a timed interaction. 66 : * 67 : * @retval Status. Callers are expected to send a status response if the 68 : * return status is not Status::Success. 69 : */ 70 : Protocols::InteractionModel::Status OnWriteRequest(Messaging::ExchangeContext * apExchangeContext, 71 : System::PacketBufferHandle && aPayload, bool aIsTimedWrite); 72 : 73 : /** 74 : * Clean up state when we are done sending the write response. 75 : */ 76 : void Close(); 77 : 78 11882 : bool IsFree() const { return mState == State::Uninitialized; } 79 : 80 100 : ~WriteHandler() override = default; 81 : 82 : CHIP_ERROR ProcessAttributeDataIBs(TLV::TLVReader & aAttributeDataIBsReader); 83 : CHIP_ERROR ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttributeDataIBsReader); 84 : 85 : CHIP_ERROR AddStatus(const ConcreteDataAttributePath & aPath, const Protocols::InteractionModel::Status aStatus); 86 : 87 : CHIP_ERROR AddClusterSpecificSuccess(const ConcreteDataAttributePath & aAttributePathParams, uint8_t aClusterStatus); 88 : 89 : CHIP_ERROR AddClusterSpecificFailure(const ConcreteDataAttributePath & aAttributePathParams, uint8_t aClusterStatus); 90 : 91 : FabricIndex GetAccessingFabricIndex() const; 92 : 93 : /** 94 : * Check whether the WriteRequest we are handling is a timed write. 95 : */ 96 0 : bool IsTimedWrite() const { return mIsTimedRequest; } 97 : 98 : bool MatchesExchangeContext(Messaging::ExchangeContext * apExchangeContext) const 99 : { 100 : return !IsFree() && mExchangeCtx.Get() == apExchangeContext; 101 : } 102 : 103 2434 : void CacheACLCheckResult(const AttributeAccessToken & aToken) { mACLCheckCache.SetValue(aToken); } 104 : 105 2434 : bool ACLCheckCacheHit(const AttributeAccessToken & aToken) 106 : { 107 2434 : return mACLCheckCache.HasValue() && mACLCheckCache.Value() == aToken; 108 : } 109 : 110 12 : bool IsCurrentlyProcessingWritePath(const ConcreteAttributePath & aPath) 111 : { 112 12 : return mProcessingAttributePath.HasValue() && mProcessingAttributePath.Value() == aPath; 113 : } 114 : 115 : private: 116 : friend class TestWriteInteraction; 117 : enum class State 118 : { 119 : Uninitialized = 0, // The handler has not been initialized 120 : Initialized, // The handler has been initialized and is ready 121 : AddStatus, // The handler has added status code 122 : Sending, // The handler has sent out the write response 123 : }; 124 : using Status = Protocols::InteractionModel::Status; 125 : Status ProcessWriteRequest(System::PacketBufferHandle && aPayload, bool aIsTimedWrite); 126 : Status HandleWriteRequestMessage(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload, 127 : bool aIsTimedWrite); 128 : 129 : CHIP_ERROR FinalizeMessage(System::PacketBufferTLVWriter && aMessageWriter, System::PacketBufferHandle & packet); 130 : CHIP_ERROR SendWriteResponse(System::PacketBufferTLVWriter && aMessageWriter); 131 : 132 : void MoveToState(const State aTargetState); 133 : const char * GetStateStr() const; 134 : 135 : void DeliverListWriteBegin(const ConcreteAttributePath & aPath); 136 : void DeliverListWriteEnd(const ConcreteAttributePath & aPath, bool writeWasSuccessful); 137 : 138 : // Deliver the signal that we have delivered all list entries to the AttributeAccessInterface. This function will be called 139 : // after handling the last chunk of a series of write requests. Or the write handler was shutdown (usually due to transport 140 : // timeout). 141 : // This function will become no-op on group writes, since DeliverFinalListWriteEndForGroupWrite will clear the 142 : // mProcessingAttributePath after processing the AttributeDataIBs from the request. 143 : void DeliverFinalListWriteEnd(bool writeWasSuccessful); 144 : 145 : // Deliver the signal that we have delivered all list entries to the AttributeAccessInterface. This function will be called 146 : // after handling the last attribute in a group write request (since group writes will never be chunked writes). Or we failed to 147 : // process the group write request (usually due to malformed messages). This function should only be called by 148 : // ProcessGroupAttributeDataIBs. 149 : CHIP_ERROR DeliverFinalListWriteEndForGroupWrite(bool writeWasSuccessful); 150 : 151 : CHIP_ERROR AddStatus(const ConcreteDataAttributePath & aPath, const StatusIB & aStatus); 152 : 153 : private: 154 : // ExchangeDelegate 155 : CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader, 156 : System::PacketBufferHandle && aPayload) override; 157 : void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override; 158 : 159 : Messaging::ExchangeHolder mExchangeCtx; 160 : WriteResponseMessage::Builder mWriteResponseBuilder; 161 : State mState = State::Uninitialized; 162 : bool mIsTimedRequest = false; 163 : bool mSuppressResponse = false; 164 : bool mHasMoreChunks = false; 165 : Optional<ConcreteAttributePath> mProcessingAttributePath; 166 : bool mProcessingAttributeIsList = false; 167 : // We record the Status when AddStatus is called to determine whether all data of a list write is accepted. 168 : // This value will be used by DeliverListWriteEnd and DeliverFinalListWriteEnd but it won't be used by group writes based on the 169 : // fact that the errors that won't be delivered to AttributeAccessInterface are: 170 : // (1) Attribute not found 171 : // (2) Access control failed 172 : // (3) Write request to a read-only attribute 173 : // (4) Data version mismatch 174 : // (5) Not using timed write. 175 : // Where (1)-(3) will be consistent among the whole list write request, while (4) and (5) are not appliable to group writes. 176 : bool mAttributeWriteSuccessful = false; 177 : Optional<AttributeAccessToken> mACLCheckCache = NullOptional; 178 : }; 179 : } // namespace app 180 : } // namespace chip