Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020-2021 Project CHIP Authors 4 : * Copyright (c) 2016-2017 Nest Labs, Inc. 5 : * All rights reserved. 6 : * 7 : * Licensed under the Apache License, Version 2.0 (the "License"); 8 : * you may not use this file except in compliance with the License. 9 : * You may obtain a copy of the License at 10 : * 11 : * http://www.apache.org/licenses/LICENSE-2.0 12 : * 13 : * Unless required by applicable law or agreed to in writing, software 14 : * distributed under the License is distributed on an "AS IS" BASIS, 15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 : * See the License for the specific language governing permissions and 17 : * limitations under the License. 18 : */ 19 : 20 : /** 21 : * @file 22 : * This file defines the circular buffer for TLV 23 : * elements. When used as the backing store for the TLVReader and 24 : * TLVWriter, those classes will work with the wraparound of data 25 : * within the buffer. Additionally, the TLVWriter will be able 26 : * to continually add top-level TLV elements by evicting 27 : * pre-existing elements. 28 : */ 29 : 30 : #pragma once 31 : 32 : #include <lib/core/CHIPError.h> 33 : #include <lib/core/TLVBackingStore.h> 34 : #include <lib/core/TLVReader.h> 35 : #include <lib/core/TLVWriter.h> 36 : #include <lib/support/DLLUtil.h> 37 : 38 : #include <stdint.h> 39 : #include <stdlib.h> 40 : 41 : namespace chip { 42 : namespace TLV { 43 : 44 : /** 45 : * @class TLVCircularBuffer 46 : * 47 : * @brief 48 : * TLVCircularBuffer provides circular storage for the 49 : * chip::TLV::TLVWriter and chip::TLVTLVReader. chip::TLV::TLVWriter is able to write an 50 : * unbounded number of TLV entries to the TLVCircularBuffer 51 : * as long as each individual TLV entry fits entirely within the 52 : * provided storage. The chip::TLV::TLVReader will read at most the size of 53 : * the buffer, but will accommodate the wraparound within the 54 : * buffer. 55 : * 56 : */ 57 : class DLL_EXPORT TLVCircularBuffer : public chip::TLV::TLVBackingStore 58 : { 59 : public: 60 : TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength); 61 : TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength, uint8_t * inHead); 62 : 63 : void Init(uint8_t * inBuffer, uint32_t inBufferLength); 64 : inline uint8_t * QueueHead() const { return mQueueHead; } 65 7732 : inline uint8_t * QueueTail() const { return mQueue + ((static_cast<size_t>(mQueueHead - mQueue) + mQueueLength) % mQueueSize); } 66 4978 : inline uint32_t DataLength() const { return mQueueLength; } 67 3281 : inline uint32_t AvailableDataLength() const { return mQueueSize - mQueueLength; } 68 1366 : inline uint32_t GetTotalDataLength() const { return mQueueSize; } 69 12 : inline uint8_t * GetQueue() const { return mQueue; } 70 : 71 : CHIP_ERROR EvictHead(); 72 : 73 : // chip::TLV::TLVBackingStore overrides: 74 : CHIP_ERROR OnInit(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen) override; 75 : CHIP_ERROR GetNextBuffer(TLVReader & ioReader, const uint8_t *& outBufStart, uint32_t & outBufLen) override; 76 : CHIP_ERROR OnInit(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen) override; 77 : CHIP_ERROR GetNewBuffer(TLVWriter & ioWriter, uint8_t *& outBufStart, uint32_t & outBufLen) override; 78 : CHIP_ERROR FinalizeBuffer(TLVWriter & ioWriter, uint8_t * inBufStart, uint32_t inBufLen) override; 79 : 80 : /** 81 : * @typedef CHIP_ERROR (*ProcessEvictedElementFunct)(TLVCircularBuffer &inBuffer, void * inAppData, TLVReader &inReader) 82 : * 83 : * A function that is called to process a TLV element prior to it 84 : * being evicted from the chip::TLV::TLVCircularBuffer 85 : * 86 : * Functions of this type are used to process a TLV element about 87 : * to be evicted from the buffer. The function will be given a 88 : * chip::TLV::TLVReader positioned on the element about to be deleted, as 89 : * well as void * context where the user may have provided 90 : * additional environment for the callback. If the function 91 : * processed the element successfully, it must return 92 : * #CHIP_NO_ERROR ; this signifies to the TLVCircularBuffer 93 : * that the element may be safely evicted. Any other return 94 : * value is treated as an error and will prevent the 95 : * #TLVCircularBuffer from evicting the element under 96 : * consideration. 97 : * 98 : * Note: This callback may be used to force 99 : * TLVCircularBuffer to not evict the element. This may be 100 : * useful in a number of circumstances, when it is desired to 101 : * have an underlying circular buffer, but not to override any 102 : * elements within it. 103 : * 104 : * @param[in] inBuffer A reference to the buffer from which the 105 : * eviction takes place 106 : * 107 : * @param[in] inAppData A pointer to the user-provided structure 108 : * containing additional context for this 109 : * callback 110 : * 111 : * @param[in] inReader A TLVReader positioned at the element to 112 : * be evicted. 113 : * 114 : * @retval #CHIP_NO_ERROR On success. Element will be evicted. 115 : * 116 : * @retval other An error has occurred during the event 117 : * processing. The element stays in the 118 : * buffer. The write function that 119 : * triggered this element eviction will 120 : * fail. 121 : */ 122 : typedef CHIP_ERROR (*ProcessEvictedElementFunct)(TLVCircularBuffer & inBuffer, void * inAppData, TLVReader & inReader); 123 : 124 : uint32_t mImplicitProfileId; 125 : void * mAppData; /**< An optional, user supplied context to be used with the callback processing the evicted element. */ 126 : ProcessEvictedElementFunct 127 : mProcessEvictedElement; /**< An optional, user-supplied callback that processes the element prior to evicting it from the 128 : circular buffer. See the ProcessEvictedElementFunct type definition on additional information on 129 : implementing the mProcessEvictedElement function. */ 130 : 131 : protected: 132 : /** 133 : * @brief 134 : * returns the actual state of what our current available buffer space is 135 : * 136 : * @param[out] outBufStart The pointer to the current buffer 137 : * 138 : * @param[out] outBufLen The available length for writing 139 : */ 140 : void GetCurrentWritableBuffer(uint8_t *& outBufStart, uint32_t & outBufLen) const; 141 : 142 : private: 143 : uint8_t * mQueue; 144 : uint32_t mQueueSize; 145 : uint8_t * mQueueHead; 146 : uint32_t mQueueLength; 147 : }; 148 : 149 : class DLL_EXPORT CircularTLVReader : public TLVReader 150 : { 151 : public: 152 : /** 153 : * @brief 154 : * Initializes a TLVReader object to read from a single TLVCircularBuffer 155 : * 156 : * Parsing begins at the start of the buffer (obtained by the 157 : * buffer->Start() position) and continues until the end of the buffer 158 : * Parsing may wraparound within the buffer (on any element). At most 159 : * buffer->GetQueueSize() bytes are read out. 160 : * 161 : * @param[in] buf A pointer to a fully initialized TLVCircularBuffer 162 : * 163 : */ 164 3044 : void Init(TLVCircularBuffer & buf) { TLVReader::Init(buf, buf.DataLength()); } 165 : }; 166 : 167 : class DLL_EXPORT CircularTLVWriter : public TLVWriter 168 : { 169 : public: 170 : /** 171 : * @brief 172 : * Initializes a TLVWriter object to write from a single TLVCircularBuffer 173 : * 174 : * Writing begins at the last byte of the buffer. The number of bytes 175 : * to be written is not constrained by the underlying circular buffer: 176 : * writing new elements to the buffer will kick out previous elements 177 : * as long as an individual top-level TLV structure fits within the 178 : * buffer. For example, writing a 7-byte top-level boolean TLV into a 179 : * 7 byte buffer will work indefinitely, but writing an 8-byte TLV 180 : * structure will result in an error. 181 : * 182 : * @param[in] buf A pointer to a fully initialized TLVCircularBuffer 183 : * 184 : */ 185 1084 : void Init(TLVCircularBuffer & buf) { TLVWriter::Init(buf, UINT32_MAX); } 186 : }; 187 : 188 : } // namespace TLV 189 : } // namespace chip