OpenVPN 3 Core Library
Loading...
Searching...
No Matches
buffer.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// These templates define the fundamental data buffer classes used by the
13// OpenVPN core. Normally OpenVPN uses buffers of unsigned chars, but the
14// templatization of the classes would allow buffers of other types to
15// be defined.
16//
17// Fundamentally a buffer is an object with 4 fields:
18//
19// 1. a pointer to underlying data array
20// 2. the capacity of the underlying data array
21// 3. an offset into the data array
22// 4. the size of the referenced data within the array
23//
24// The BufferType template is the lowest-level buffer class template. It refers
25// to a buffer but without any notion of ownership of the underlying data.
26//
27// The BufferAllocatedType template is a higher-level template that inherits
28// from BufferType but which asserts ownership over the resources of the buffer --
29// for example, it will free the underlying buffer in its destructor.
30//
31// Since most of the time, we want our buffers to be made out of unsigned chars,
32// some typedefs at the end of the file define common instantations for the
33// BufferType and BufferAllocatedType templates.
34//
35// Buffer : a simple buffer of unsigned char without ownership semantics
36// ConstBuffer : like buffer but where the data pointed to by the buffer is read-only
37// BufferAllocated : an allocated Buffer with ownership semantics
38// BufferPtr : a smart, reference-counted pointer to a BufferAllocatedRc
39
40#pragma once
41
42#include <string>
43#include <cstdlib> // defines std::abort()
44#include <cstring>
45#include <algorithm>
46#include <type_traits> // for std::is_nothrow_move_constructible_v, std::remove_const, std::enable_if_t, and std::is_const_v
47
48#ifndef OPENVPN_NO_IO
49#include <openvpn/io/io.hpp>
50#endif
51
54#include <openvpn/common/rc.hpp>
58
59#ifdef OPENVPN_BUFFER_ABORT
60#define OPENVPN_BUFFER_THROW(exc) \
61 { \
62 std::abort(); \
63 }
64#else
65#define OPENVPN_BUFFER_THROW(exc) \
66 { \
67 throw BufferException(BufferException::exc); \
68 }
69#endif
70
71namespace openvpn {
72// ===============================================================================================
73// special-purpose exception class for Buffer classes
74// ===============================================================================================
75
114class BufferException : public std::exception
115{
116 public:
132
134 : status_(status)
135 {
136 }
137
138 BufferException(Status status, const std::string &msg)
139 : status_(status),
140 msg_(std::string(status_string(status)) + " : " + msg)
141 {
142 }
143
144 const char *what() const noexcept override
145 {
146 if (!msg_.empty())
147 return msg_.c_str();
148 else
149 return status_string(status_);
150 }
151
153 {
154 return status_;
155 }
156 virtual ~BufferException() noexcept = default;
157
158 private:
159 static const char *status_string(const Status status)
160 {
161 switch (status)
162 {
163 case buffer_full:
164 return "buffer_full";
165 case buffer_headroom:
166 return "buffer_headroom";
167 case buffer_underflow:
168 return "buffer_underflow";
169 case buffer_overflow:
170 return "buffer_overflow";
171 case buffer_offset:
172 return "buffer_offset";
173 case buffer_index:
174 return "buffer_index";
176 return "buffer_const_index";
178 return "buffer_push_front_headroom";
180 return "buffer_no_reset_impl";
181 case buffer_pop_back:
182 return "buffer_pop_back";
183 case buffer_set_size:
184 return "buffer_set_size";
185 case buffer_range:
186 return "buffer_range";
187 default:
188 return "buffer_???";
189 }
190 }
191
193 std::string msg_;
194};
195
196// ===============================================================================================
197// ===============================================================================================
198
199template <typename T>
201
202template <typename T>
203class BufferType;
204
205// Allocation and security for the buffer
206struct BufferFlags : IntrinsicType<BufferFlags, unsigned int>
207{
208 using IntrinsicType<BufferFlags, unsigned int>::IntrinsicType;
209};
210
211// ===============================================================================================
212// class ConstBufferType
213// ===============================================================================================
234template <typename T>
236{
237 public:
238 typedef T value_type;
239 typedef T *type;
240 typedef const T *const_type;
241 typedef typename std::remove_const_t<T> NCT;
242
247
258 ConstBufferType(void *data, const size_t size, const bool filled);
259
267 template <typename U = T,
268 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
269 ConstBufferType(const void *data, const size_t size, const bool filled);
270
277 ConstBufferType(T *data, const size_t size, const bool filled);
278
286 template <typename U = T,
287 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
288 ConstBufferType(const U *data, const size_t size, const bool filled);
289
294 virtual ~ConstBufferType() = default;
295
301 const auto &operator[](const size_t index) const;
302
308 auto &operator[](const size_t index);
309
314 void init_headroom(const size_t headroom);
315
320 void reset_offset(const size_t offset);
321
326
331
336 const T *c_str() const;
337
342 size_t length() const;
343
348 const T *c_data() const;
349
354 const T *c_data_end() const;
355
360 const T *c_data_raw() const;
361
366 size_t capacity() const;
367
372 size_t offset() const;
373
378 bool defined() const;
379
384 bool allocated() const;
385
390 bool empty() const;
391
396 size_t size() const;
397
403
409
414 T front() const;
415
420 T back() const;
421
426 void advance(const size_t delta);
427
432 bool contains_null() const;
433
438 bool is_zeroed() const;
439
440#ifndef OPENVPN_NO_IO
445 openvpn_io::const_buffer const_buffer() const;
446
456 openvpn_io::const_buffer const_buffer_clamp() const;
457
468 openvpn_io::const_buffer const_buffer_limit(const size_t limit) const;
469#endif
470
476 void read(NCT *data, const size_t size);
477
483 void read(void *data, const size_t size);
484
490 auto *read_alloc(const size_t size);
491
497 auto read_alloc_buf(const size_t size);
498
503 size_t max_size() const;
504
509 void set_size(const size_t size);
510
515 void inc_size(const size_t delta);
516
523 ConstBufferType range(size_t offset, size_t len) const;
524
530 const T *c_index(const size_t index) const;
531
537 bool operator==(const ConstBufferType &other) const;
538
544 bool operator!=(const ConstBufferType &other) const;
545
546 protected: // mutable implementations are only available to derived classes
551 void reserve(const size_t n);
552
557 T *data();
558
564
570
576 size_t remaining(const size_t tailroom = 0) const;
577
583 size_t max_size_tailroom(const size_t tailroom) const;
584
589 void push_back(const T &value);
590
595 void push_front(const T &value);
596
604 void set_trailer(const T &value);
605
611
617 T *index(const size_t index);
618
619#ifndef OPENVPN_NO_IO
625 openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom = 0);
626
632 openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom = 0);
633
639 openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom = 0);
640
646 openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom = 0);
647#endif
648
655 void realign(size_t headroom);
656
662 void write(const T *data, const size_t size);
663
669 void write(const void *data, const size_t size);
670
676 void prepend(const T *data, const size_t size);
677
683 void prepend(const void *data, const size_t size);
684
690 T *write_alloc(const size_t size);
691
700 T *prepend_alloc(const size_t size);
701
707 void reset(const size_t min_capacity, const BufferFlags flags);
708
715 void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags);
716
722 template <typename B>
723 void append(const B &other);
724
730 template <typename T_>
732
738 void buffer_full_error(const size_t newcap, const bool allocated) const;
739
746 virtual void reset_impl(const size_t min_capacity, const BufferFlags flags);
747
754 virtual void resize(const size_t new_capacity);
755
763 ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity);
764
774 template <typename U = T,
775 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
776 ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity);
777
778 private:
779 // Even though *data_ is declared as non-const, within ConstBufferType
780 // we MUST always treat it as const. But derived classes may treat it
781 // as non-const as long as they passed in non-const data to begin with.
782 T *data_; // pointer to data
783 size_t offset_; // offset from data_ of beginning of T array (to allow for headroom)
784 size_t size_; // number of T objects in array starting at data_ + offset_
785 size_t capacity_; // maximum number of array objects of type T for which memory is allocated, starting at data_
786};
787
788// ===============================================================================================
789// class BufferType
790// ===============================================================================================
791
792template <typename T>
794{
795 private:
796 template <typename>
797 friend class ConstBufferType;
798
799 public:
800 using ConstBufferType<T>::empty;
803 using ConstBufferType<T>::back;
805 using ConstBufferType<T>::operator[];
807 using ConstBufferType<T>::data;
816 using ConstBufferType<T>::index;
817#ifndef OPENVPN_NO_IO
822#endif
824 using ConstBufferType<T>::write;
828 using ConstBufferType<T>::reset;
833
837 BufferType() = default;
838
845 BufferType(void *data, const size_t size, const bool filled)
846 : ConstBufferType<T>(data, size, filled) {};
847
854 BufferType(T *data, const size_t size, const bool filled)
855 : ConstBufferType<T>(data, size, filled) {};
856
864 protected:
865 BufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
867};
868
869// ===============================================================================================
870// class BufferAllocatedType
871// ===============================================================================================
872
873// Flag constants
874namespace BufAllocFlags {
875constexpr BufferFlags NO_FLAGS(0u);
876constexpr BufferFlags CONSTRUCT_ZERO(1u << 0);
877constexpr BufferFlags DESTRUCT_ZERO(1u << 1);
878constexpr BufferFlags GROW(1u << 2);
879constexpr BufferFlags ARRAY(1u << 3);
880} // namespace BufAllocFlags
881
882template <typename T>
884{
885 private:
886 // Friend to all specializations of this template allows access to other.data_
887 template <typename>
889
890 public:
893 using BufferType<T>::size;
894 using BufferType<T>::capacity;
895 using BufferType<T>::offset;
896 using BufferType<T>::data_raw;
897 using BufferType<T>::c_data_raw;
898 using BufferType<T>::data;
899 using BufferType<T>::c_data;
900 using BufferType<T>::swap;
901
906
912 explicit BufferAllocatedType(const size_t capacity,
914
921 explicit BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags);
922
928
935 template <typename T_>
938
943 void operator=(const BufferAllocatedType &other);
944
951
958 void init(const T *data, const size_t size, const BufferFlags flags);
959
964 void realloc(const size_t newcap);
965
973 BufferAllocatedType &realign(const size_t headroom);
974
980 void reset(const size_t min_capacity, const BufferFlags flags = BufAllocFlags::NO_FLAGS);
981
988 void reset(const size_t headroom,
989 const size_t min_capacity,
991
998 template <typename T_>
1000
1007 template <typename T_>
1009
1016 template <typename T_>
1018
1025
1029 void clear();
1030
1036 bool test_flags(const BufferFlags flags) const noexcept;
1037
1043
1050
1055
1064 const size_t size,
1065 const size_t capacity,
1066 const BufferFlags flags);
1067
1073 void reset_impl(const size_t min_capacity, const BufferFlags flags) override;
1074
1079 void resize(const size_t new_capacity) override;
1080
1086 void realloc_(const size_t newcap, size_t new_offset);
1087
1092
1093 private:
1095};
1096
1097// ===============================================================================================
1098// ConstBufferType<T> member function definitions
1099// ===============================================================================================
1100
1101template <typename T>
1103{
1104 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1105 "class ConstBufferType not noexcept move constructable");
1106 data_ = nullptr;
1107 offset_ = size_ = capacity_ = 0;
1108}
1109
1110template <typename T>
1111ConstBufferType<T>::ConstBufferType(void *data, const size_t size, const bool filled)
1112 : ConstBufferType((T *)data, size, filled){};
1113
1114template <typename T>
1115template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1116ConstBufferType<T>::ConstBufferType(const void *data, const size_t size, const bool filled)
1117 : ConstBufferType(const_cast<void *>(data), size, filled){};
1118
1119template <typename T>
1120ConstBufferType<T>::ConstBufferType(T *data, const size_t size, const bool filled)
1121 : data_(data),
1122 offset_(0),
1123 size_(filled ? size : 0),
1124 capacity_(size){};
1125
1126template <typename T>
1127template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1128ConstBufferType<T>::ConstBufferType(const U *data, const size_t size, const bool filled)
1129 : ConstBufferType(const_cast<U *>(data), size, filled){};
1130
1131template <typename T>
1132const auto &ConstBufferType<T>::operator[](const size_t index) const
1133{
1134 if (index >= size_)
1135 OPENVPN_BUFFER_THROW(buffer_const_index);
1136 return c_data()[index];
1137}
1138
1139template <typename T>
1140auto &ConstBufferType<T>::operator[](const size_t index)
1141{
1142 if (index >= size_)
1143 OPENVPN_BUFFER_THROW(buffer_const_index);
1144 if constexpr (std::is_same_v<ConstBufferType<T>, decltype(*this)>)
1145 return c_data()[index];
1146 else
1147 return data()[index];
1148}
1149
1150template <typename T>
1151void ConstBufferType<T>::init_headroom(const size_t headroom)
1152{
1153 if (headroom > capacity_)
1154 OPENVPN_BUFFER_THROW(buffer_headroom);
1155 offset_ = headroom;
1156 size_ = 0;
1157}
1158
1159template <typename T>
1160void ConstBufferType<T>::reset_offset(const size_t offset)
1161{
1162 const size_t size = size_ + offset_ - offset;
1163 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1164 OPENVPN_BUFFER_THROW(buffer_offset);
1165 offset_ = offset;
1166 size_ = size;
1167}
1168
1169template <typename T>
1171{
1172 size_ = 0;
1173}
1174
1175template <typename T>
1177{
1178 offset_ = size_ = 0;
1179}
1180
1181template <typename T>
1183{
1184 return c_data();
1185}
1186
1187template <typename T>
1189{
1190 return size();
1191}
1192
1193template <typename T>
1195{
1196 return data_ + offset_;
1197}
1198
1199template <typename T>
1201{
1202 return data_ + offset_ + size_;
1203}
1204
1205template <typename T>
1207{
1208 return data_;
1209}
1210
1211template <typename T>
1213{
1214 return capacity_;
1215}
1216
1217template <typename T>
1219{
1220 return offset_;
1221}
1222
1223template <typename T>
1225{
1226 return size_ > 0;
1227}
1228
1229template <typename T>
1231{
1232 return data_ != nullptr;
1233}
1234
1235template <typename T>
1237{
1238 return !size_;
1239}
1240
1241template <typename T>
1243{
1244 return size_;
1245}
1246
1247template <typename T>
1249{
1250 if (!size_)
1251 OPENVPN_BUFFER_THROW(buffer_pop_back);
1252 return *(c_data() + (--size_));
1253}
1254
1255template <typename T>
1257{
1258 T ret = (*this)[0];
1259 ++offset_;
1260 --size_;
1261 return ret;
1262}
1263
1264template <typename T>
1266{
1267 return (*this)[0];
1268}
1269
1270template <typename T>
1272{
1273 return (*this)[size_ - 1];
1274}
1275
1276template <typename T>
1277void ConstBufferType<T>::advance(const size_t delta)
1278{
1279 if (delta > size_)
1280 OPENVPN_BUFFER_THROW(buffer_overflow);
1281 offset_ += delta;
1282 size_ -= delta;
1283}
1284
1285template <typename T>
1287{
1288 const T *end = c_data_end();
1289 for (const T *p = c_data(); p < end; ++p)
1290 {
1291 if (!*p)
1292 return true;
1293 }
1294 return false;
1295}
1296
1297template <typename T>
1299{
1300 const T *end = c_data_end();
1301 for (const T *p = c_data(); p < end; ++p)
1302 {
1303 if (*p)
1304 return false;
1305 }
1306 return true;
1307}
1308
1309#ifndef OPENVPN_NO_IO
1310
1311template <typename T>
1312openvpn_io::const_buffer ConstBufferType<T>::const_buffer() const
1313{
1314 return openvpn_io::const_buffer(c_data(), size());
1315}
1316
1317template <typename T>
1318openvpn_io::const_buffer ConstBufferType<T>::const_buffer_clamp() const
1319{
1320 return openvpn_io::const_buffer(c_data(), buf_clamp_write(size()));
1321}
1322
1323template <typename T>
1324openvpn_io::const_buffer ConstBufferType<T>::const_buffer_limit(const size_t limit) const
1325{
1326 return openvpn_io::const_buffer(c_data(), std::min(buf_clamp_write(size()), limit));
1327}
1328#endif
1329
1330template <typename T>
1331void ConstBufferType<T>::read(NCT *data, const size_t size)
1332{
1333 std::memcpy(data, read_alloc(size), size * sizeof(T));
1334}
1335
1336template <typename T>
1337void ConstBufferType<T>::read(void *data, const size_t size)
1338{
1339 read((NCT *)data, size);
1340}
1341
1342template <typename T>
1343auto *ConstBufferType<T>::read_alloc(const size_t size)
1344{
1345 if (size <= size_)
1346 {
1347 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, const value_type, value_type>;
1348 retT *ret;
1349 if constexpr (std::is_const_v<retT>)
1350 ret = c_data();
1351 else
1352 ret = data();
1353 offset_ += size;
1354 size_ -= size;
1355 return ret;
1356 }
1357 else
1358 OPENVPN_BUFFER_THROW(buffer_underflow);
1359}
1360
1361template <typename T>
1363{
1364 if (size <= size_)
1365 {
1366 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, ConstBufferType<T>, BufferType<T>>;
1367 retT ret(data_, offset_, size, capacity_);
1368 offset_ += size;
1369 size_ -= size;
1370 return ret;
1371 }
1372 else
1373 OPENVPN_BUFFER_THROW(buffer_underflow);
1374}
1375
1376template <typename T>
1378{
1379 const size_t r = capacity_ - offset_;
1380 return r <= capacity_ ? r : 0;
1381}
1382
1383template <typename T>
1384void ConstBufferType<T>::set_size(const size_t size)
1385{
1386 if (size > max_size())
1387 OPENVPN_BUFFER_THROW(buffer_set_size);
1388 size_ = size;
1389}
1390
1391template <typename T>
1392void ConstBufferType<T>::inc_size(const size_t delta)
1393{
1394 set_size(size_ + delta);
1395}
1396
1397template <typename T>
1398ConstBufferType<T> ConstBufferType<T>::range(size_t offset, size_t len) const
1399{
1400 if (offset + len > size())
1401 {
1402 if (offset < size())
1403 len = size() - offset;
1404 else
1405 len = 0;
1406 }
1407 return ConstBufferType(c_data(), offset, len, len);
1408}
1409
1410template <typename T>
1411const T *ConstBufferType<T>::c_index(const size_t index) const
1412{
1413 if (index >= size_)
1414 OPENVPN_BUFFER_THROW(buffer_const_index);
1415 return &c_data()[index];
1416}
1417
1418template <typename T>
1419template <typename T_>
1421{
1422 std::swap(other.data_, data_);
1423 std::swap(other.offset_, offset_);
1424 std::swap(other.size_, size_);
1425 std::swap(other.capacity_, capacity_);
1426}
1427
1428template <typename T>
1430{
1431 if (size_ != other.size_)
1432 return false;
1433 return std::memcmp(c_data(), other.c_data(), size_) == 0;
1434}
1435
1436template <typename T>
1438{
1439 return !(*this == other);
1440}
1441
1442template <typename T>
1444{
1445 if (n > capacity_)
1446 resize(n);
1447}
1448
1449template <typename T>
1451{
1452 return data_ + offset_;
1453}
1454
1455template <typename T>
1457{
1458 return data_ + offset_ + size_;
1459}
1460
1461template <typename T>
1463{
1464 return data_;
1465}
1466
1467template <typename T>
1468size_t ConstBufferType<T>::remaining(const size_t tailroom) const
1469{
1470 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1471 return r <= capacity_ ? r : 0;
1472}
1473
1474template <typename T>
1475size_t ConstBufferType<T>::max_size_tailroom(const size_t tailroom) const
1476{
1477 const size_t r = capacity_ - (offset_ + tailroom);
1478 return r <= capacity_ ? r : 0;
1479}
1480
1481template <typename T>
1483{
1484 if (!remaining())
1485 resize(offset_ + size_ + 1);
1486 *(data() + size_++) = value;
1487}
1488
1489template <typename T>
1491{
1492 if (!offset_)
1493 OPENVPN_BUFFER_THROW(buffer_push_front_headroom);
1494 --offset_;
1495 ++size_;
1496 *data() = value;
1497}
1498
1499template <typename T>
1501{
1502 if (!remaining())
1503 resize(offset_ + size_ + 1);
1504 *(data() + size_) = value;
1505}
1506
1507template <typename T>
1509{
1510 if (empty() || back())
1511 push_back(0);
1512}
1513
1514template <typename T>
1515T *ConstBufferType<T>::index(const size_t index)
1516{
1517 if (index >= size_)
1518 OPENVPN_BUFFER_THROW(buffer_index);
1519 return &data()[index];
1520}
1521
1522
1523#ifndef OPENVPN_NO_IO
1524
1525template <typename T>
1526openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer(const size_t tailroom)
1527{
1528 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1529}
1530
1531template <typename T>
1532openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append(const size_t tailroom)
1533{
1534 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1535}
1536
1537template <typename T>
1538openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_clamp(const size_t tailroom)
1539{
1540 return openvpn_io::mutable_buffer(data(), buf_clamp_read(max_size_tailroom(tailroom)));
1541}
1542
1543template <typename T>
1544openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append_clamp(const size_t tailroom)
1545{
1546 return openvpn_io::mutable_buffer(data_end(), buf_clamp_read(remaining(tailroom)));
1547}
1548#endif
1549
1550template <typename T>
1551void ConstBufferType<T>::realign(size_t headroom)
1552{
1553 if (headroom != offset_)
1554 {
1555 if (headroom + size_ > capacity_)
1556 OPENVPN_BUFFER_THROW(buffer_headroom);
1557 std::memmove(data_ + headroom, data_ + offset_, size_);
1558 offset_ = headroom;
1559 }
1560}
1561
1562template <typename T>
1563void ConstBufferType<T>::write(const T *data, const size_t size)
1564{
1565 std::memcpy(write_alloc(size), data, size * sizeof(T));
1566}
1567
1568template <typename T>
1569void ConstBufferType<T>::write(const void *data, const size_t size)
1570{
1571 write((const T *)data, size);
1572}
1573
1574template <typename T>
1575void ConstBufferType<T>::prepend(const T *data, const size_t size)
1576{
1577 std::memcpy(prepend_alloc(size), data, size * sizeof(T));
1578}
1579
1580template <typename T>
1581void ConstBufferType<T>::prepend(const void *data, const size_t size)
1582{
1583 prepend((const T *)data, size);
1584}
1585
1586template <typename T>
1588{
1589 if (size > remaining())
1590 resize(offset_ + size_ + size);
1591 T *ret = data() + size_;
1592 size_ += size;
1593 return ret;
1594}
1595
1596template <typename T>
1597T *ConstBufferType<T>::prepend_alloc(const size_t request_size)
1598{
1599 if (request_size > offset())
1600 realign(request_size);
1601
1602 offset_ -= request_size;
1603 size_ += request_size;
1604
1605 return data();
1606}
1607
1608template <typename T>
1609void ConstBufferType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1610{
1611 if (min_capacity > capacity_)
1612 reset_impl(min_capacity, flags);
1613}
1614
1615template <typename T>
1616void ConstBufferType<T>::reset(const size_t headroom,
1617 const size_t min_capacity,
1618 const BufferFlags flags)
1619{
1620 reset(min_capacity, flags);
1621 init_headroom(headroom);
1622}
1623
1624template <typename T>
1625template <typename B>
1626void ConstBufferType<T>::append(const B &other)
1627{
1628 write(other.c_data(), other.size());
1629}
1630
1631template <typename T>
1632void ConstBufferType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1633{
1634 OPENVPN_BUFFER_THROW(buffer_no_reset_impl);
1635}
1636
1637template <typename T>
1638void ConstBufferType<T>::resize(const size_t new_capacity)
1639{
1640 if (new_capacity > capacity_)
1641 buffer_full_error(new_capacity, false);
1642}
1643
1644template <typename T>
1645void ConstBufferType<T>::buffer_full_error(const size_t newcap, const bool allocated) const
1646{
1647#ifdef OPENVPN_BUFFER_ABORT
1648 std::abort();
1649#else
1650 throw BufferException(BufferException::buffer_full, "allocated=" + std::to_string(allocated) + " size=" + std::to_string(size_) + " offset=" + std::to_string(offset_) + " capacity=" + std::to_string(capacity_) + " newcap=" + std::to_string(newcap));
1651#endif
1652}
1653
1654template <typename T>
1655ConstBufferType<T>::ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
1656 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1657
1658template <typename T>
1659template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1660ConstBufferType<T>::ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
1661 : ConstBufferType(const_cast<U *>(data), offset, size, capacity){};
1662
1663// ===============================================================================================
1664// BufferAllocatedType<T> member function definitions
1665// ===============================================================================================
1666
1667template <typename T>
1669 const size_t size,
1670 const size_t capacity,
1671 const BufferFlags flags)
1672 : BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(flags)
1673{
1675 std::memset(data_raw(), 0, capacity * sizeof(T));
1676}
1677
1678template <typename T>
1680 : BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS)
1681{
1682 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1683 "class BufferAllocatedType not noexcept move constructable");
1684}
1685
1686template <typename T>
1688 const BufferFlags flags)
1690 (flags & BufAllocFlags::ARRAY ? capacity : 0),
1691 capacity,
1692 flags){};
1693
1694template <typename T>
1696 const size_t size,
1697 const BufferFlags flags)
1698 : BufferAllocatedType(0, size, size, flags)
1699{
1700 if (size && data)
1701 std::memcpy(data_raw(), data, size * sizeof(T));
1702}
1703
1704template <typename T>
1706 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), other.flags_)
1707{
1708 if (size())
1709 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1710}
1711
1712template <typename T>
1713template <typename T_>
1715 const BufferFlags flags)
1716 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), flags)
1717{
1718 static_assert(sizeof(T) == sizeof(T_), "size inconsistency");
1719 if (size())
1720 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1721}
1722
1723template <typename T>
1725{
1726 if (this != &other)
1727 {
1728 auto tempBuffer = BufferAllocatedType(other.offset(),
1729 other.size(),
1730 other.capacity(),
1731 other.flags_);
1732 if (other.size())
1733 std::memcpy(tempBuffer.data(), other.c_data(), tempBuffer.size() * sizeof(T));
1734 swap(tempBuffer);
1735 }
1736}
1737
1738template <typename T>
1739void BufferAllocatedType<T>::init(const size_t capacity, const BufferFlags flags)
1740{
1741 auto tempBuffer = BufferAllocatedType(capacity, flags);
1742 swap(tempBuffer);
1743}
1744
1745template <typename T>
1746void BufferAllocatedType<T>::init(const T *data, const size_t size, const BufferFlags flags)
1747{
1748 auto tempBuffer = BufferAllocatedType(data, size, flags);
1749 swap(tempBuffer);
1750}
1751
1752template <typename T>
1753void BufferAllocatedType<T>::realloc(const size_t newcap)
1754{
1755 if (newcap > capacity())
1756 realloc_(newcap, offset());
1757}
1758
1759template <typename T>
1761{
1762 if (headroom != offset())
1763 {
1764 if (headroom + size() > capacity())
1765 realloc_(headroom + size(), headroom);
1766 else
1767 BufferType<T>::realign(headroom);
1768 }
1769 return *this;
1770}
1771
1772template <typename T>
1773void BufferAllocatedType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1774{
1775 if (min_capacity > capacity())
1776 init(min_capacity, flags);
1777}
1778
1779template <typename T>
1780void BufferAllocatedType<T>::reset(const size_t headroom,
1781 const size_t min_capacity,
1782 const BufferFlags flags)
1783{
1784 reset(min_capacity, flags);
1785 init_headroom(headroom);
1786}
1787
1788template <typename T>
1789template <typename T_>
1791{
1792 auto temp = BufferAllocatedType();
1793 swap(other);
1794 other.swap(temp);
1795}
1796
1797template <typename T>
1798template <typename T_>
1800{
1801 BufferType<T>::swap(other);
1802 std::swap(flags_, other.flags_);
1803}
1804
1805template <typename T>
1806template <typename T_>
1809{
1810 move(other);
1811}
1812
1813template <typename T>
1815{
1816 if (this != &other)
1817 {
1818 move(other);
1819 }
1820 return *this;
1821}
1822
1823template <typename T>
1825{
1826 auto tempBuffer = BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS);
1827 swap(tempBuffer);
1828}
1829
1830template <typename T>
1832{
1833 return flags_ & flags;
1834}
1835
1836template <typename T>
1838{
1839 flags_ |= flags;
1840}
1841
1842template <typename T>
1844{
1845 flags_ &= ~flags;
1846}
1847
1848template <typename T>
1850{
1851 if (data_raw())
1852 free_data();
1853}
1854
1855template <typename T>
1856void BufferAllocatedType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1857{
1858 init(min_capacity, flags);
1859}
1860
1861template <typename T>
1862void BufferAllocatedType<T>::resize(const size_t new_capacity)
1863{
1864 const size_t newcap = std::max(new_capacity, capacity() * 2);
1865 if (newcap > capacity())
1866 {
1867 if (flags_ & BufAllocFlags::GROW)
1868 realloc_(newcap, offset());
1869 else
1870 buffer_full_error(newcap, true);
1871 }
1872}
1873
1874template <typename T>
1875void BufferAllocatedType<T>::realloc_(const size_t newcap, size_t new_offset)
1876{
1877 auto tempBuffer = BufferAllocatedType(new_offset, size(), newcap, flags_);
1878 if (size())
1879 std::memcpy(tempBuffer.data(), c_data(), size() * sizeof(T));
1880 swap(tempBuffer);
1881}
1882
1883template <typename T>
1885{
1886 if (size() && (flags_ & BufAllocFlags::DESTRUCT_ZERO))
1887 std::memset(data_raw(), 0, capacity() * sizeof(T));
1888 delete[] data_raw();
1889}
1890
1891// ===============================================================================================
1892// specializations of BufferType for unsigned char
1893// ===============================================================================================
1894
1900
1901// ===============================================================================================
1902// BufferAllocated + RC with thread-safe refcount
1903// ===============================================================================================
1904
1907
1908// ===============================================================================================
1909// Deduction guide - needed to deduce converting ctor
1910// ===============================================================================================
1911
1912template <typename T_>
1914
1915// ===============================================================================================
1916// cast BufferType<T> to ConstBufferType<T>
1917// ===============================================================================================
1918
1919template <typename T>
1921{
1922 return src;
1923}
1924
1925template <typename T>
1927{
1928 return src;
1929}
1930
1931// ===============================================================================================
1932// Buffer related utilities - consider moving to a separate file
1933// ===============================================================================================
1934
1942template <typename AlignT, typename T>
1943inline AlignT *align_as(BufferAllocatedType<T> &buf) // TODO: Could be implemented noexcept
1944{
1945 /* The standard requires that alignof(T) is a power of 2, and that any allocation will be
1946 aligned to at least alignof(std::max_align_t), so I assume offset zero in a buffer is
1947 aligned and therefore there is no need to check for alignment of the buffer itself.
1948
1949 This means a suitable address exists in the first alignof(std::max_align_t) so we never have
1950 to increase the offset at all. This is a simplification that might not hold in all cases,
1951 but it is a reasonable assumption for now. Given that, we can just align the buffer by
1952 masking out the lower bits of the current data address (computation of align_ptr below)
1953 and then realign the buffer to that address if needed. This will preserve as much of the
1954 headroom as possible.
1955 */
1956 auto data_ptr = reinterpret_cast<uintptr_t>(buf.c_data()); // Current data address in integral form
1957 auto align_ptr = data_ptr & ~(alignof(AlignT) - 1); // 'Previous' aligned address
1958 auto raw_data_ptr = reinterpret_cast<uintptr_t>(buf.c_data_raw()); // Start of allocated buffer
1959
1960 if (align_ptr != data_ptr && align_ptr >= raw_data_ptr)
1961 buf.realign(align_ptr - raw_data_ptr);
1962
1963 return reinterpret_cast<AlignT *>(buf.data()); // unsigned char is type accessible by all types
1964}
1965
1966} // namespace openvpn
#define OPENVPN_BUFFER_THROW(exc)
Definition buffer.hpp:65
BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const BufferFlags flags)
Private constructor.
Definition buffer.hpp:1668
friend class BufferAllocatedType
Definition buffer.hpp:888
void clear()
Clears the contents of the buffer.
Definition buffer.hpp:1824
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
Definition buffer.hpp:1814
void reset(const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1773
void init(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Initializes the buffer with the specified capacity and flags.
Definition buffer.hpp:1739
void clear_flags(const BufferFlags flags)
Clears the specified flags for the buffer.
Definition buffer.hpp:1843
BufferAllocatedType(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType with the specified capacity and flags.
Definition buffer.hpp:1687
void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified headroom, minimum capacity, and flags.
Definition buffer.hpp:1780
~BufferAllocatedType()
Destructor.
Definition buffer.hpp:1849
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
Definition buffer.hpp:1862
bool test_flags(const BufferFlags flags) const noexcept
Test if the buffer has the specified flags.
Definition buffer.hpp:1831
void add_flags(const BufferFlags flags)
Sets the specified flags for the buffer.
Definition buffer.hpp:1837
void move(BufferAllocatedType< T_ > &other)
Moves the contents of another BufferAllocatedType object into this object.
Definition buffer.hpp:1790
BufferAllocatedType()
Default constructor.
Definition buffer.hpp:1679
void realloc(const size_t newcap)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1753
void operator=(const BufferAllocatedType &other)
Assignment operator.
Definition buffer.hpp:1724
void reset_impl(const size_t min_capacity, const BufferFlags flags) override
Resets the buffer implementation with the specified minimum capacity and flags.
Definition buffer.hpp:1856
void init(const T *data, const size_t size, const BufferFlags flags)
Initializes the buffer with the specified data, size, and flags.
Definition buffer.hpp:1746
void realloc_(const size_t newcap, size_t new_offset)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1875
BufferAllocatedType & realign(const size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1760
void free_data()
Frees the data associated with the buffer.
Definition buffer.hpp:1884
void swap(BufferAllocatedType< T_ > &other)
Swaps the contents of this BufferAllocatedType object with another BufferAllocatedType object.
Definition buffer.hpp:1799
BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
Definition buffer.hpp:1695
BufferAllocatedType(const BufferAllocatedType &other)
Copy constructor.
Definition buffer.hpp:1705
BufferAllocatedType(const BufferType< T_ > &other, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType from a BufferType object with the specified flags.
Definition buffer.hpp:1714
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
Definition buffer.hpp:1807
report various types of exceptions or errors that may occur when working with buffers
Definition buffer.hpp:115
const char * what() const noexcept override
Definition buffer.hpp:144
virtual ~BufferException() noexcept=default
BufferException(Status status)
Definition buffer.hpp:133
Status status() const
Definition buffer.hpp:152
BufferException(Status status, const std::string &msg)
Definition buffer.hpp:138
static const char * status_string(const Status status)
Definition buffer.hpp:159
BufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Protected constructor for BufferType that takes a T pointer, offset, size, and capacity.
Definition buffer.hpp:865
BufferType()=default
Default constructor for BufferType.
BufferType(T *data, const size_t size, const bool filled)
Constructor for BufferType that takes a T pointer, size, and a flag indicating if the buffer is fille...
Definition buffer.hpp:854
BufferType(void *data, const size_t size, const bool filled)
Constructor for BufferType that takes a void pointer, size, and a flag indicating if the buffer is fi...
Definition buffer.hpp:845
Immutable buffer with double ended access and adjustable free space at both ends.
Definition buffer.hpp:236
bool defined() const
Returns true if the buffer is not empty.
Definition buffer.hpp:1224
void set_trailer(const T &value)
Place a T object after the last object in the array, with possible resize to contain it....
Definition buffer.hpp:1500
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1194
T * prepend_alloc(const size_t size)
Allocate space for prepending data to the buffer.
Definition buffer.hpp:1597
ConstBufferType(void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a void pointer and size.
Definition buffer.hpp:1111
T * data_end()
Get a mutable pointer to the end of the array.
Definition buffer.hpp:1456
void append(const B &other)
Append data from another buffer to this buffer.
Definition buffer.hpp:1626
void init_headroom(const size_t headroom)
Initializes the headroom (offset) of the buffer.
Definition buffer.hpp:1151
void inc_size(const size_t delta)
Increment the size of the array (usually used in a similar context to set_size such as after mutable_...
Definition buffer.hpp:1392
size_t length() const
Returns the length of the buffer.
Definition buffer.hpp:1188
std::remove_const_t< T > NCT
Definition buffer.hpp:241
openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom=0)
Return an openvpn_io::mutable_buffer object used by asio read methods, starting from data().
Definition buffer.hpp:1526
size_t max_size() const
Return the maximum allowable size value in T objects given the current offset (without considering re...
Definition buffer.hpp:1377
openvpn_io::const_buffer const_buffer_limit(const size_t limit) const
Return a const_buffer object with a specified size limit.
Definition buffer.hpp:1324
T front() const
Returns the first element of the buffer.
Definition buffer.hpp:1265
virtual void reset_impl(const size_t min_capacity, const BufferFlags flags)
Called when the reset method needs to expand the buffer size.
Definition buffer.hpp:1632
ConstBufferType()
Default constructor for ConstBufferType.
Definition buffer.hpp:1102
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
Definition buffer.hpp:1312
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
Definition buffer.hpp:1482
void reset(const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1609
T back() const
Returns the last element of the buffer.
Definition buffer.hpp:1271
ConstBufferType(const U *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a const pointer to T and size. This constructor is disabled when T ...
Definition buffer.hpp:1128
openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer_append().
Definition buffer.hpp:1544
ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object.
Definition buffer.hpp:1655
bool operator!=(const ConstBufferType &other) const
Inequality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1437
ConstBufferType(T *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a pointer to T and size.
Definition buffer.hpp:1120
void write(const void *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1569
ConstBufferType range(size_t offset, size_t len) const
Get a range of the buffer as a ConstBufferType object.
Definition buffer.hpp:1398
void read(void *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1337
ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object from a const U* pointer. This constructor is disabled when T is al...
Definition buffer.hpp:1660
const T * c_str() const
Returns a const pointer to the null-terminated string representation of the buffer.
Definition buffer.hpp:1182
T * write_alloc(const size_t size)
Allocate space for writing data to the buffer.
Definition buffer.hpp:1587
void reserve(const size_t n)
Reserve additional memory for the buffer.
Definition buffer.hpp:1443
const T * c_data_end() const
Returns a const pointer to the end of the buffer.
Definition buffer.hpp:1200
auto read_alloc_buf(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1362
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1575
bool allocated() const
Returns true if the data memory is defined (allocated).
Definition buffer.hpp:1230
size_t capacity() const
Returns the capacity (raw size) of the allocated buffer in T objects.
Definition buffer.hpp:1212
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
ConstBufferType(const void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a const void pointer and size. This constructor is disabled when T ...
Definition buffer.hpp:1116
T pop_back()
Removes and returns the last element from the buffer.
Definition buffer.hpp:1248
openvpn_io::const_buffer const_buffer_clamp() const
Return a clamped version of const_buffer().
Definition buffer.hpp:1318
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1277
const auto & operator[](const size_t index) const
Const indexing operator for ConstBufferType.
Definition buffer.hpp:1132
bool operator==(const ConstBufferType &other) const
Equality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1429
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1236
void prepend(const void *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1581
const T * c_data_raw() const
Returns a const pointer to the start of the raw data in the buffer.
Definition buffer.hpp:1206
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1563
const T * c_index(const size_t index) const
Get a const pointer to the element at the specified index in the array.
Definition buffer.hpp:1411
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1343
bool is_zeroed() const
Returns true if the buffer is zeroed (all elements are zero).
Definition buffer.hpp:1298
T pop_front()
Removes and returns the first element from the buffer.
Definition buffer.hpp:1256
size_t remaining(const size_t tailroom=0) const
Return the number of additional T objects that can be added before capacity is reached (without consi...
Definition buffer.hpp:1468
auto & operator[](const size_t index)
Non-const indexing operator for ConstBufferType.
Definition buffer.hpp:1140
T * data_raw()
Get a mutable pointer to the start of the raw data.
Definition buffer.hpp:1462
void swap(ConstBufferType< T_ > &other)
Swap the contents of this buffer with another buffer.
Definition buffer.hpp:1420
size_t offset() const
Returns the current offset (headroom) into the buffer.
Definition buffer.hpp:1218
void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified headroom, minimum capacity, and flags.
Definition buffer.hpp:1616
void buffer_full_error(const size_t newcap, const bool allocated) const
Throw an exception when the buffer is full.
Definition buffer.hpp:1645
void reset_offset(const size_t offset)
Resets the offset of the buffer.
Definition buffer.hpp:1160
virtual ~ConstBufferType()=default
Needed because this class has virtual member functions and is intended as a base class.
T * index(const size_t index)
Get a mutable index into the array.
Definition buffer.hpp:1515
bool contains_null() const
Returns true if the buffer contains a null character.
Definition buffer.hpp:1286
void push_front(const T &value)
Append a T object to the array, with possible resize.
Definition buffer.hpp:1490
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1384
void reset_content()
Resets the content of the buffer.
Definition buffer.hpp:1176
virtual void resize(const size_t new_capacity)
Derived classes can implement buffer growing semantics by overloading this method....
Definition buffer.hpp:1638
void null_terminate()
Null-terminate the array.
Definition buffer.hpp:1508
void reset_size()
Resets the size of the buffer to zero.
Definition buffer.hpp:1170
void realign(size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1551
openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer().
Definition buffer.hpp:1538
openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom=0)
Return an openvpn_io::mutable_buffer object used by asio read methods, starting from data_end().
Definition buffer.hpp:1532
size_t max_size_tailroom(const size_t tailroom) const
Return the maximum allowable size value in T objects, taking into account the specified tailroom.
Definition buffer.hpp:1475
void read(NCT *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1331
A class template that enables reference counting for a given type.
Definition make_rc.hpp:29
constexpr BufferFlags GROW(1u<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
constexpr BufferFlags CONSTRUCT_ZERO(1u<< 0)
if enabled, constructors/init will zero allocated space
constexpr BufferFlags ARRAY(1u<< 3)
if enabled, use as array
constexpr BufferFlags NO_FLAGS(0u)
no flags set
constexpr BufferFlags DESTRUCT_ZERO(1u<< 1)
if enabled, destructor will zero data before deletion
ConstBufferType< T > & const_buffer_ref(BufferType< T > &src)
Definition buffer.hpp:1920
AlignT * align_as(BufferAllocatedType< T > &buf)
Aligns buffer.data() to the required value and returns a pointer to the aligned object.
Definition buffer.hpp:1943
size_t buf_clamp_read(const size_t size)
Definition bufclamp.hpp:23
size_t buf_clamp_write(const size_t size)
Definition bufclamp.hpp:32
CRTP type designed to allow creation of strong types based on intrinsics.
reroute_gw flags
server addresses push_back({address, port})
std::string ret
#define msg(flags,...)