libtins  4.0
memory_helpers.h
1 /*
2  * Copyright (c) 2017, Matias Fontanini
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #ifndef TINS_MEMORY_HELPERS_H
31 #define TINS_MEMORY_HELPERS_H
32 
33 #include <stdint.h>
34 #include <cstring>
35 #include <vector>
36 #include <tins/exceptions.h>
37 #include <tins/endianness.h>
38 
39 namespace Tins {
40 
41 class IPv4Address;
42 class IPv6Address;
43 template <size_t n>
44 class HWAddress;
45 
49 namespace Memory {
50 
51 inline void read_data(const uint8_t* buffer, uint8_t* output_buffer, size_t size) {
52  std::memcpy(output_buffer, buffer, size);
53 }
54 
55 template <typename T>
56 void read_value(const uint8_t* buffer, T& value) {
57  std::memcpy(&value, buffer, sizeof(value));
58 }
59 
60 inline void write_data(uint8_t* buffer, const uint8_t* ptr, size_t size) {
61  std::memcpy(buffer, ptr, size);
62 }
63 
64 template <typename T>
65 void write_value(uint8_t* buffer, const T& value) {
66  std::memcpy(buffer, &value, sizeof(value));
67 }
68 
69 class InputMemoryStream {
70 public:
71  InputMemoryStream(const uint8_t* buffer, size_t total_sz)
72  : buffer_(buffer), size_(total_sz) {
73  }
74 
75  InputMemoryStream(const std::vector<uint8_t>& data) : buffer_(&data[0]), size_(data.size()) {
76  }
77 
78  template <typename T>
79  T read() {
80  T output;
81  read(output);
82  return output;
83  }
84 
85  template <typename T>
86  T read_le() {
87  return Endian::le_to_host(read<T>());
88  }
89 
90  template <typename T>
91  T read_be() {
92  return Endian::be_to_host(read<T>());
93  }
94 
95  template <typename T>
96  void read(T& value) {
97  if (!can_read(sizeof(value))) {
98  throw malformed_packet();
99  }
100  read_value(buffer_, value);
101  skip(sizeof(value));
102  }
103 
104  void skip(size_t size) {
105  if (TINS_UNLIKELY(size > size_)) {
106  throw malformed_packet();
107  }
108  buffer_ += size;
109  size_ -= size;
110  }
111 
112  bool can_read(size_t byte_count) const {
113  return TINS_LIKELY(size_ >= byte_count);
114  }
115 
116  void read(void* output_buffer, size_t output_buffer_size) {
117  if (!can_read(output_buffer_size)) {
118  throw malformed_packet();
119  }
120  read_data(buffer_, (uint8_t*)output_buffer, output_buffer_size);
121  skip(output_buffer_size);
122  }
123 
124  const uint8_t* pointer() const {
125  return buffer_;
126  }
127 
128  size_t size() const {
129  return size_;
130  }
131 
132  void size(size_t new_size) {
133  size_ = new_size;
134  }
135 
136  operator bool() const {
137  return size_ > 0;
138  }
139 
140  void read(std::vector<uint8_t>& value, size_t count);
141  void read(HWAddress<6>& address);
142  void read(IPv4Address& address);
143  void read(IPv6Address& address);
144 private:
145  const uint8_t* buffer_;
146  size_t size_;
147 };
148 
149 class OutputMemoryStream {
150 public:
151  OutputMemoryStream(uint8_t* buffer, size_t total_sz)
152  : buffer_(buffer), size_(total_sz) {
153  }
154 
155  OutputMemoryStream(std::vector<uint8_t>& buffer)
156  : buffer_(&buffer[0]), size_(buffer.size()) {
157  }
158 
159  template <typename T>
160  void write(const T& value) {
161  if (TINS_UNLIKELY(size_ < sizeof(value))) {
162  throw serialization_error();
163  }
164  write_value(buffer_, value);
165  skip(sizeof(value));
166  }
167 
168  template <typename T>
169  void write_be(const T& value) {
170  write(Endian::host_to_be(value));
171  }
172 
173  template <typename T>
174  void write_le(const T& value) {
175  write(Endian::host_to_le(value));
176  }
177 
178  template <typename ForwardIterator>
179  void write(ForwardIterator start, ForwardIterator end) {
180  const size_t length = std::distance(start, end);
181  if (TINS_UNLIKELY(size_ < length)) {
182  throw serialization_error();
183  }
184  // VC doesn't like dereferencing empty vector's iterators so check this here
185  if (TINS_UNLIKELY(length == 0)) {
186  return;
187  }
188  std::memcpy(buffer_, &*start, length);
189  skip(length);
190  }
191 
192  void skip(size_t size) {
193  if (TINS_UNLIKELY(size > size_)) {
194  throw malformed_packet();
195  }
196  buffer_ += size;
197  size_ -= size;
198  }
199 
200  void write(const uint8_t* ptr, size_t length) {
201  write(ptr, ptr + length);
202  }
203 
204  void fill(size_t size, uint8_t value) {
205  if (TINS_UNLIKELY(size_ < size)) {
206  throw serialization_error();
207  }
208  std::memset(buffer_, value, size);
209  skip(size);
210  }
211 
212  uint8_t* pointer() {
213  return buffer_;
214  }
215 
216  size_t size() const {
217  return size_;
218  }
219 
220  void write(const HWAddress<6>& address);
221  void write(const IPv4Address& address);
222  void write(const IPv6Address& address);
223 private:
224  uint8_t* buffer_;
225  size_t size_;
226 };
227 
232 } // Memory
233 } // Tins
234 
235 #endif // TINS_MEMORY_HELPERS_H
The Tins namespace.
Definition: address_range.h:38