1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef MESSAGE_BUFFER_H_ 18 #define MESSAGE_BUFFER_H_ 19 20 #include <cstdint> 21 #include <memory> 22 #include <tuple> 23 24 #include "android-base/macros.h" 25 26 #include "wifilogd/local_utils.h" 27 28 namespace android { 29 namespace wifilogd { 30 31 // A fixed-size buffer, which provides FIFO access to read and write 32 // a sequence of messages. 33 class MessageBuffer { 34 public: 35 // A wrapper which guarantees that a MessageBuffer will be rewound, 36 // when the program exits the wrapper's scope. The user must ensure that 37 // |buffer| does not expire before the ScopedRewinder. 38 class ScopedRewinder { 39 public: ScopedRewinder(NONNULL MessageBuffer * buffer)40 explicit ScopedRewinder(NONNULL MessageBuffer* buffer) : buffer_(buffer) {} ~ScopedRewinder()41 ~ScopedRewinder() { buffer_->Rewind(); } 42 43 private: 44 MessageBuffer* const buffer_; 45 }; 46 47 // Constructs the buffer. |size| must be greater than GetHeaderSize(). 48 explicit MessageBuffer(size_t size); 49 50 // Appends a single message to the buffer. |data_len| must be >=1. Returns 51 // true if the message was added to the buffer. 52 bool Append(NONNULL const uint8_t* data, uint16_t data_len); 53 54 // Returns true if the buffer is large enough to hold |length| bytes of user 55 // data, when the buffer is empty. 56 bool CanFitEver(uint16_t length) const; 57 58 // Returns true if the buffer currently has enough free space to hold |length| 59 // bytes of user data. 60 bool CanFitNow(uint16_t length) const; 61 62 // Clears the buffer. An immediately following read operation will return an 63 // empty message. An immediately following write operation will write to the 64 // head of the buffer. Clearing may be lazy (i.e., underlying storage is not 65 // necessarily zeroed). 66 void Clear(); 67 68 // Returns the first unread message in the buffer. If there is no such 69 // message, returns {nullptr, 0}. MessageBuffer retains ownership of the 70 // message's storage. 71 std::tuple<const uint8_t*, size_t> ConsumeNextMessage(); 72 73 // Returns the size of MessageBuffer's per-message header. GetHeaderSize()74 static constexpr size_t GetHeaderSize() { return sizeof(LengthHeader); } 75 76 // Returns the total available free space in the buffer. This may be 77 // larger than the usable space, due to overheads. GetFreeSize()78 size_t GetFreeSize() const { return capacity_ - write_pos_; } 79 80 // Resets the read pointer to the start of the buffer. An immediately 81 // following read will return the first message in the buffer. An immediately 82 // following write, however, will be placed at the same position as if 83 // Rewind() had not been called. 84 void Rewind(); 85 86 private: 87 struct LengthHeader { 88 uint16_t payload_len; 89 }; 90 91 // Prepares a header, and writes that header into the buffer. 92 void AppendHeader(uint16_t message_len); 93 94 // Writes arbitrary data into the buffer. 95 void AppendRawBytes(NONNULL const void* data_start, size_t data_len); 96 97 // Returns the total number of bytes available for reading. This number 98 // includes headers. GetReadableSize()99 size_t GetReadableSize() const { return write_pos_ - read_pos_; } 100 101 const std::unique_ptr<uint8_t[]> data_; 102 const size_t capacity_; 103 size_t read_pos_; 104 size_t write_pos_; 105 106 // MessageBuffer is a value type, so it would be semantically reasonable to 107 // support copy and assign. Performance-wise, though, we should avoid 108 // copies. Remove the copy constructor and the assignment operator, to 109 // ensure that we don't accidentally make copies. 110 DISALLOW_COPY_AND_ASSIGN(MessageBuffer); 111 }; 112 113 } // namespace wifilogd 114 } // namespace android 115 116 #endif // MESSAGE_BUFFER_H_ 117