libtins 4.5
Loading...
Searching...
No Matches
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
39namespace Tins {
40
41class IPv4Address;
42class IPv6Address;
43template <size_t n>
44class HWAddress;
45
49namespace Memory {
50
51inline void read_data(const uint8_t* buffer, uint8_t* output_buffer, size_t size) {
52 std::memcpy(output_buffer, buffer, size);
53}
54
55template <typename T>
56void read_value(const uint8_t* buffer, T& value) {
57 std::memcpy(&value, buffer, sizeof(value));
58}
59
60inline void write_data(uint8_t* buffer, const uint8_t* ptr, size_t size) {
61 std::memcpy(buffer, ptr, size);
62}
63
64template <typename T>
65void write_value(uint8_t* buffer, const T& value) {
66 std::memcpy(buffer, &value, sizeof(value));
67}
68
69class InputMemoryStream {
70public:
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);
144private:
145 const uint8_t* buffer_;
146 size_t size_;
147};
148
149class OutputMemoryStream {
150public:
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);
223private:
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