19d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal/*
29d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * Copyright (C) 2016 The Android Open Source Project
39d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal *
49d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * Licensed under the Apache License, Version 2.0 (the "License");
59d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * you may not use this file except in compliance with the License.
69d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * You may obtain a copy of the License at
79d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal *
89d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal *      http://www.apache.org/licenses/LICENSE-2.0
99d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal *
109d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * Unless required by applicable law or agreed to in writing, software
119d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * distributed under the License is distributed on an "AS IS" BASIS,
129d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * See the License for the specific language governing permissions and
149d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal * limitations under the License.
159d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal */
169d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
179d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#ifndef MESSAGE_BUFFER_H_
189d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#define MESSAGE_BUFFER_H_
199d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
209d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#include <cstdint>
219d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#include <memory>
226d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal#include <tuple>
239d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
249d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#include "android-base/macros.h"
259d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
26fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal#include "wifilogd/local_utils.h"
27fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
289d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawalnamespace android {
299d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawalnamespace wifilogd {
309d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
319d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal// A fixed-size buffer, which provides FIFO access to read and write
329d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal// a sequence of messages.
339d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawalclass MessageBuffer {
349d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal public:
35fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal  // A wrapper which guarantees that a MessageBuffer will be rewound,
36fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal  // when the program exits the wrapper's scope. The user must ensure that
37fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal  // |buffer| does not expire before the ScopedRewinder.
38fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal  class ScopedRewinder {
39fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal   public:
40fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal    explicit ScopedRewinder(NONNULL MessageBuffer* buffer) : buffer_(buffer) {}
41fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal    ~ScopedRewinder() { buffer_->Rewind(); }
42fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal
43fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal   private:
44fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal    MessageBuffer* const buffer_;
45fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal  };
46fd08064ec7ca120b3501c341c8dfde9fdd757316mukesh agrawal
479d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // Constructs the buffer. |size| must be greater than GetHeaderSize().
489d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  explicit MessageBuffer(size_t size);
499d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
50fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // Appends a single message to the buffer. |data_len| must be >=1. Returns
51fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // true if the message was added to the buffer.
52fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  bool Append(NONNULL const uint8_t* data, uint16_t data_len);
53fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
540e465b480b9067a9795139a0aa1f4144d10c485emukesh agrawal  // Returns true if the buffer is large enough to hold |length| bytes of user
550e465b480b9067a9795139a0aa1f4144d10c485emukesh agrawal  // data, when the buffer is empty.
560e465b480b9067a9795139a0aa1f4144d10c485emukesh agrawal  bool CanFitEver(uint16_t length) const;
570e465b480b9067a9795139a0aa1f4144d10c485emukesh agrawal
58fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // Returns true if the buffer currently has enough free space to hold |length|
59fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // bytes of user data.
60fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  bool CanFitNow(uint16_t length) const;
61fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
6269690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal  // Clears the buffer. An immediately following read operation will return an
6369690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal  // empty message. An immediately following write operation will write to the
6469690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal  // head of the buffer. Clearing may be lazy (i.e., underlying storage is not
6569690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal  // necessarily zeroed).
6669690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal  void Clear();
6769690078fa70e031b80f8760f3c69f0884e42d08mukesh agrawal
686d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal  // Returns the first unread message in the buffer. If there is no such
696d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal  // message, returns {nullptr, 0}. MessageBuffer retains ownership of the
706d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal  // message's storage.
716d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal  std::tuple<const uint8_t*, size_t> ConsumeNextMessage();
726d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal
739d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // Returns the size of MessageBuffer's per-message header.
749d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  static constexpr size_t GetHeaderSize() { return sizeof(LengthHeader); }
759d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
76fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // Returns the total available free space in the buffer. This may be
77fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // larger than the usable space, due to overheads.
78fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  size_t GetFreeSize() const { return capacity_ - write_pos_; }
79fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
805f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal  // Resets the read pointer to the start of the buffer. An immediately
815f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal  // following read will return the first message in the buffer. An immediately
825f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal  // following write, however, will be placed at the same position as if
835f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal  // Rewind() had not been called.
845f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal  void Rewind();
855f88ee735e1cf0c12f96c3add65d798ec58ad4bdmukesh agrawal
869d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal private:
879d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  struct LengthHeader {
889d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal    uint16_t payload_len;
899d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  };
909d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
91fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // Prepares a header, and writes that header into the buffer.
92fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  void AppendHeader(uint16_t message_len);
93fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
94fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  // Writes arbitrary data into the buffer.
95fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  void AppendRawBytes(NONNULL const void* data_start, size_t data_len);
96fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal
97b0ef31514a28871bf7d2435e4b5aada60e813ce1mukesh agrawal  // Returns the total number of bytes available for reading. This number
98b0ef31514a28871bf7d2435e4b5aada60e813ce1mukesh agrawal  // includes headers.
99b0ef31514a28871bf7d2435e4b5aada60e813ce1mukesh agrawal  size_t GetReadableSize() const { return write_pos_ - read_pos_; }
100b0ef31514a28871bf7d2435e4b5aada60e813ce1mukesh agrawal
101b1af0126828f129002e28659de6d52803323b671mukesh agrawal  const std::unique_ptr<uint8_t[]> data_;
102b1af0126828f129002e28659de6d52803323b671mukesh agrawal  const size_t capacity_;
1036d8e2206e972a5f7512d5e2c558e9c23c77169f0mukesh agrawal  size_t read_pos_;
104fd65102c2bb8b5a4cfa7d9ddff7d5f6c5d08e623mukesh agrawal  size_t write_pos_;
1059d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
1069d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // MessageBuffer is a value type, so it would be semantically reasonable to
1079d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // support copy and assign. Performance-wise, though, we should avoid
1089d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // copies. Remove the copy constructor and the assignment operator, to
1099d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  // ensure that we don't accidentally make copies.
1109d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal  DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
1119d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal};
1129d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
1139d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal}  // namespace wifilogd
1149d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal}  // namespace android
1159d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal
1169d2165f7a9c41bb0081036d4ef5b9d5150fa3684mukesh agrawal#endif  // MESSAGE_BUFFER_H_
117