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