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>
57
58#ifdef OPENVPN_BUFFER_ABORT
59#define OPENVPN_BUFFER_THROW(exc) \
60 { \
61 std::abort(); \
62 }
63#else
64#define OPENVPN_BUFFER_THROW(exc) \
65 { \
66 throw BufferException(BufferException::exc); \
67 }
68#endif
69
70namespace openvpn {
71// ===============================================================================================
72// special-purpose exception class for Buffer classes
73// ===============================================================================================
74
113class BufferException : public std::exception
114{
115 public:
131
133 : status_(status)
134 {
135 }
136
137 BufferException(Status status, const std::string &msg)
138 : status_(status),
139 msg_(std::string(status_string(status)) + " : " + msg)
140 {
141 }
142
143 const char *what() const noexcept override
144 {
145 if (!msg_.empty())
146 return msg_.c_str();
147 else
148 return status_string(status_);
149 }
150
152 {
153 return status_;
154 }
155 virtual ~BufferException() noexcept = default;
156
157 private:
158 static const char *status_string(const Status status)
159 {
160 switch (status)
161 {
162 case buffer_full:
163 return "buffer_full";
164 case buffer_headroom:
165 return "buffer_headroom";
166 case buffer_underflow:
167 return "buffer_underflow";
168 case buffer_overflow:
169 return "buffer_overflow";
170 case buffer_offset:
171 return "buffer_offset";
172 case buffer_index:
173 return "buffer_index";
175 return "buffer_const_index";
177 return "buffer_push_front_headroom";
179 return "buffer_no_reset_impl";
180 case buffer_pop_back:
181 return "buffer_pop_back";
182 case buffer_set_size:
183 return "buffer_set_size";
184 case buffer_range:
185 return "buffer_range";
186 default:
187 return "buffer_???";
188 }
189 }
190
192 std::string msg_;
193};
194
195// ===============================================================================================
196// ===============================================================================================
197
198template <typename T>
200
201template <typename T>
202class BufferType;
203
204// ===============================================================================================
205// class ConstBufferType
206// ===============================================================================================
227template <typename T>
229{
230 public:
231 typedef T value_type;
232 typedef T *type;
233 typedef const T *const_type;
234 typedef typename std::remove_const_t<T> NCT;
235
240
251 ConstBufferType(void *data, const size_t size, const bool filled);
252
260 template <typename U = T,
261 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
262 ConstBufferType(const void *data, const size_t size, const bool filled);
263
270 ConstBufferType(T *data, const size_t size, const bool filled);
271
279 template <typename U = T,
280 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
281 ConstBufferType(const U *data, const size_t size, const bool filled);
282
287 virtual ~ConstBufferType() = default;
288
294 const auto &operator[](const size_t index) const;
295
301 auto &operator[](const size_t index);
302
307 void init_headroom(const size_t headroom);
308
313 void reset_offset(const size_t offset);
314
319
324
329 const T *c_str() const;
330
335 size_t length() const;
336
341 const T *c_data() const;
342
347 const T *c_data_end() const;
348
353 const T *c_data_raw() const;
354
359 size_t capacity() const;
360
365 size_t offset() const;
366
371 bool defined() const;
372
377 bool allocated() const;
378
383 bool empty() const;
384
389 size_t size() const;
390
396
402
407 T front() const;
408
413 T back() const;
414
419 void advance(const size_t delta);
420
425 bool contains_null() const;
426
431 bool is_zeroed() const;
432
433#ifndef OPENVPN_NO_IO
438 openvpn_io::const_buffer const_buffer() const;
439
449 openvpn_io::const_buffer const_buffer_clamp() const;
450
461 openvpn_io::const_buffer const_buffer_limit(const size_t limit) const;
462#endif
463
469 void read(NCT *data, const size_t size);
470
476 void read(void *data, const size_t size);
477
483 auto *read_alloc(const size_t size);
484
490 auto read_alloc_buf(const size_t size);
491
496 size_t max_size() const;
497
502 void set_size(const size_t size);
503
508 void inc_size(const size_t delta);
509
516 ConstBufferType range(size_t offset, size_t len) const;
517
523 const T *c_index(const size_t index) const;
524
530 bool operator==(const ConstBufferType &other) const;
531
537 bool operator!=(const ConstBufferType &other) const;
538
539 protected: // mutable implementations are only available to derived classes
544 void reserve(const size_t n);
545
550 T *data();
551
557
563
569 size_t remaining(const size_t tailroom = 0) const;
570
576 size_t max_size_tailroom(const size_t tailroom) const;
577
582 void push_back(const T &value);
583
588 void push_front(const T &value);
589
597 void set_trailer(const T &value);
598
604
610 T *index(const size_t index);
611
612#ifndef OPENVPN_NO_IO
618 openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom = 0);
619
625 openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom = 0);
626
632 openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom = 0);
633
639 openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom = 0);
640#endif
641
648 void realign(size_t headroom);
649
655 void write(const T *data, const size_t size);
656
662 void write(const void *data, const size_t size);
663
669 void prepend(const T *data, const size_t size);
670
676 void prepend(const void *data, const size_t size);
677
683 T *write_alloc(const size_t size);
684
693 T *prepend_alloc(const size_t size);
694
700 void reset(const size_t min_capacity, const unsigned int flags);
701
708 void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags);
709
715 template <typename B>
716 void append(const B &other);
717
723 template <typename T_>
725
731 void buffer_full_error(const size_t newcap, const bool allocated) const;
732
738 virtual void reset_impl(const size_t min_capacity, const unsigned int flags);
739
746 virtual void resize(const size_t new_capacity);
747
755 ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity);
756
766 template <typename U = T,
767 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
768 ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity);
769
770 private:
771 // Even though *data_ is declared as non-const, within ConstBufferType
772 // we MUST always treat it as const. But derived classes may treat it
773 // as non-const as long as they passed in non-const data to begin with.
774 T *data_; // pointer to data
775 size_t offset_; // offset from data_ of beginning of T array (to allow for headroom)
776 size_t size_; // number of T objects in array starting at data_ + offset_
777 size_t capacity_; // maximum number of array objects of type T for which memory is allocated, starting at data_
778};
779
780// ===============================================================================================
781// class BufferType
782// ===============================================================================================
783
784template <typename T>
786{
787 private:
788 template <typename>
789 friend class ConstBufferType;
790
791 public:
792 using ConstBufferType<T>::empty;
795 using ConstBufferType<T>::back;
797 using ConstBufferType<T>::operator[];
799 using ConstBufferType<T>::data;
808 using ConstBufferType<T>::index;
809#ifndef OPENVPN_NO_IO
814#endif
816 using ConstBufferType<T>::write;
820 using ConstBufferType<T>::reset;
825
829 BufferType() = default;
830
837 BufferType(void *data, const size_t size, const bool filled)
838 : ConstBufferType<T>(data, size, filled) {};
839
846 BufferType(T *data, const size_t size, const bool filled)
847 : ConstBufferType<T>(data, size, filled) {};
848
856 protected:
857 BufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
859};
860
861// ===============================================================================================
862// class BufferAllocatedType
863// ===============================================================================================
864
865// Allocation and security for the buffer
867{
868 enum
869 {
870 CONSTRUCT_ZERO = (1 << 0),
871 DESTRUCT_ZERO = (1 << 1),
872 GROW = (1 << 2),
873 ARRAY = (1 << 3),
874 };
875};
876
877template <typename T>
879{
880 private:
881 // Friend to all specializations of this template allows access to other.data_
882 template <typename>
884
885 public:
888 using BufferType<T>::size;
889 using BufferType<T>::capacity;
890 using BufferType<T>::offset;
891 using BufferType<T>::data_raw;
892 using BufferType<T>::c_data_raw;
893 using BufferType<T>::data;
894 using BufferType<T>::c_data;
895 using BufferType<T>::swap;
896
901
907 BufferAllocatedType(const size_t capacity, const unsigned int flags);
908
915 BufferAllocatedType(const T *data, const size_t size, const unsigned int flags);
916
922
929 template <typename T_>
930 BufferAllocatedType(const BufferType<T_> &other, const unsigned int flags);
931
936 void operator=(const BufferAllocatedType &other);
937
943 void init(const size_t capacity, const unsigned int flags);
944
951 void init(const T *data, const size_t size, const unsigned int flags);
952
957 void realloc(const size_t newcap);
958
966 BufferAllocatedType &realign(const size_t headroom);
967
973 void reset(const size_t min_capacity, const unsigned int flags);
974
981 void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags);
982
989 template <typename T_>
991
998 template <typename T_>
1000
1007 template <typename T_>
1009
1016
1020 void clear();
1021
1026 void or_flags(const unsigned int flags);
1027
1032 void and_flags(const unsigned int flags);
1033
1038
1047 const size_t size,
1048 const size_t capacity,
1049 const unsigned int flags);
1050
1056 void reset_impl(const size_t min_capacity, const unsigned int flags) override;
1057
1062 void resize(const size_t new_capacity) override;
1063
1069 void realloc_(const size_t newcap, size_t new_offset);
1070
1075
1076 private:
1077 unsigned int flags_;
1078};
1079
1080// ===============================================================================================
1081// ConstBufferType<T> member function definitions
1082// ===============================================================================================
1083
1084template <typename T>
1086{
1087 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1088 "class ConstBufferType not noexcept move constructable");
1089 data_ = nullptr;
1090 offset_ = size_ = capacity_ = 0;
1091}
1092
1093template <typename T>
1094ConstBufferType<T>::ConstBufferType(void *data, const size_t size, const bool filled)
1095 : ConstBufferType((T *)data, size, filled){};
1096
1097template <typename T>
1098template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1099ConstBufferType<T>::ConstBufferType(const void *data, const size_t size, const bool filled)
1100 : ConstBufferType(const_cast<void *>(data), size, filled){};
1101
1102template <typename T>
1103ConstBufferType<T>::ConstBufferType(T *data, const size_t size, const bool filled)
1104 : data_(data),
1105 offset_(0),
1106 size_(filled ? size : 0),
1107 capacity_(size){};
1108
1109template <typename T>
1110template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1111ConstBufferType<T>::ConstBufferType(const U *data, const size_t size, const bool filled)
1112 : ConstBufferType(const_cast<U *>(data), size, filled){};
1113
1114template <typename T>
1115const auto &ConstBufferType<T>::operator[](const size_t index) const
1116{
1117 if (index >= size_)
1118 OPENVPN_BUFFER_THROW(buffer_const_index);
1119 return c_data()[index];
1120}
1121
1122template <typename T>
1123auto &ConstBufferType<T>::operator[](const size_t index)
1124{
1125 if (index >= size_)
1126 OPENVPN_BUFFER_THROW(buffer_const_index);
1127 if constexpr (std::is_same_v<ConstBufferType<T>, decltype(*this)>)
1128 return c_data()[index];
1129 else
1130 return data()[index];
1131}
1132
1133template <typename T>
1134void ConstBufferType<T>::init_headroom(const size_t headroom)
1135{
1136 if (headroom > capacity_)
1137 OPENVPN_BUFFER_THROW(buffer_headroom);
1138 offset_ = headroom;
1139 size_ = 0;
1140}
1141
1142template <typename T>
1143void ConstBufferType<T>::reset_offset(const size_t offset)
1144{
1145 const size_t size = size_ + offset_ - offset;
1146 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1147 OPENVPN_BUFFER_THROW(buffer_offset);
1148 offset_ = offset;
1149 size_ = size;
1150}
1151
1152template <typename T>
1154{
1155 size_ = 0;
1156}
1157
1158template <typename T>
1160{
1161 offset_ = size_ = 0;
1162}
1163
1164template <typename T>
1166{
1167 return c_data();
1168}
1169
1170template <typename T>
1172{
1173 return size();
1174}
1175
1176template <typename T>
1178{
1179 return data_ + offset_;
1180}
1181
1182template <typename T>
1184{
1185 return data_ + offset_ + size_;
1186}
1187
1188template <typename T>
1190{
1191 return data_;
1192}
1193
1194template <typename T>
1196{
1197 return capacity_;
1198}
1199
1200template <typename T>
1202{
1203 return offset_;
1204}
1205
1206template <typename T>
1208{
1209 return size_ > 0;
1210}
1211
1212template <typename T>
1214{
1215 return data_ != nullptr;
1216}
1217
1218template <typename T>
1220{
1221 return !size_;
1222}
1223
1224template <typename T>
1226{
1227 return size_;
1228}
1229
1230template <typename T>
1232{
1233 if (!size_)
1234 OPENVPN_BUFFER_THROW(buffer_pop_back);
1235 return *(c_data() + (--size_));
1236}
1237
1238template <typename T>
1240{
1241 T ret = (*this)[0];
1242 ++offset_;
1243 --size_;
1244 return ret;
1245}
1246
1247template <typename T>
1249{
1250 return (*this)[0];
1251}
1252
1253template <typename T>
1255{
1256 return (*this)[size_ - 1];
1257}
1258
1259template <typename T>
1260void ConstBufferType<T>::advance(const size_t delta)
1261{
1262 if (delta > size_)
1263 OPENVPN_BUFFER_THROW(buffer_overflow);
1264 offset_ += delta;
1265 size_ -= delta;
1266}
1267
1268template <typename T>
1270{
1271 const T *end = c_data_end();
1272 for (const T *p = c_data(); p < end; ++p)
1273 {
1274 if (!*p)
1275 return true;
1276 }
1277 return false;
1278}
1279
1280template <typename T>
1282{
1283 const T *end = c_data_end();
1284 for (const T *p = c_data(); p < end; ++p)
1285 {
1286 if (*p)
1287 return false;
1288 }
1289 return true;
1290}
1291
1292#ifndef OPENVPN_NO_IO
1293
1294template <typename T>
1295openvpn_io::const_buffer ConstBufferType<T>::const_buffer() const
1296{
1297 return openvpn_io::const_buffer(c_data(), size());
1298}
1299
1300template <typename T>
1301openvpn_io::const_buffer ConstBufferType<T>::const_buffer_clamp() const
1302{
1303 return openvpn_io::const_buffer(c_data(), buf_clamp_write(size()));
1304}
1305
1306template <typename T>
1307openvpn_io::const_buffer ConstBufferType<T>::const_buffer_limit(const size_t limit) const
1308{
1309 return openvpn_io::const_buffer(c_data(), std::min(buf_clamp_write(size()), limit));
1310}
1311#endif
1312
1313template <typename T>
1314void ConstBufferType<T>::read(NCT *data, const size_t size)
1315{
1316 std::memcpy(data, read_alloc(size), size * sizeof(T));
1317}
1318
1319template <typename T>
1320void ConstBufferType<T>::read(void *data, const size_t size)
1321{
1322 read((NCT *)data, size);
1323}
1324
1325template <typename T>
1326auto *ConstBufferType<T>::read_alloc(const size_t size)
1327{
1328 if (size <= size_)
1329 {
1330 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, const value_type, value_type>;
1331 retT *ret;
1332 if constexpr (std::is_const_v<retT>)
1333 ret = c_data();
1334 else
1335 ret = data();
1336 offset_ += size;
1337 size_ -= size;
1338 return ret;
1339 }
1340 else
1341 OPENVPN_BUFFER_THROW(buffer_underflow);
1342}
1343
1344template <typename T>
1346{
1347 if (size <= size_)
1348 {
1349 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, ConstBufferType<T>, BufferType<T>>;
1350 retT ret(data_, offset_, size, capacity_);
1351 offset_ += size;
1352 size_ -= size;
1353 return ret;
1354 }
1355 else
1356 OPENVPN_BUFFER_THROW(buffer_underflow);
1357}
1358
1359template <typename T>
1361{
1362 const size_t r = capacity_ - offset_;
1363 return r <= capacity_ ? r : 0;
1364}
1365
1366template <typename T>
1367void ConstBufferType<T>::set_size(const size_t size)
1368{
1369 if (size > max_size())
1370 OPENVPN_BUFFER_THROW(buffer_set_size);
1371 size_ = size;
1372}
1373
1374template <typename T>
1375void ConstBufferType<T>::inc_size(const size_t delta)
1376{
1377 set_size(size_ + delta);
1378}
1379
1380template <typename T>
1381ConstBufferType<T> ConstBufferType<T>::range(size_t offset, size_t len) const
1382{
1383 if (offset + len > size())
1384 {
1385 if (offset < size())
1386 len = size() - offset;
1387 else
1388 len = 0;
1389 }
1390 return ConstBufferType(c_data(), offset, len, len);
1391}
1392
1393template <typename T>
1394const T *ConstBufferType<T>::c_index(const size_t index) const
1395{
1396 if (index >= size_)
1397 OPENVPN_BUFFER_THROW(buffer_const_index);
1398 return &c_data()[index];
1399}
1400
1401template <typename T>
1402template <typename T_>
1404{
1405 std::swap(other.data_, data_);
1406 std::swap(other.offset_, offset_);
1407 std::swap(other.size_, size_);
1408 std::swap(other.capacity_, capacity_);
1409}
1410
1411template <typename T>
1413{
1414 if (size_ != other.size_)
1415 return false;
1416 return std::memcmp(c_data(), other.c_data(), size_) == 0;
1417}
1418
1419template <typename T>
1421{
1422 return !(*this == other);
1423}
1424
1425template <typename T>
1427{
1428 if (n > capacity_)
1429 resize(n);
1430}
1431
1432template <typename T>
1434{
1435 return data_ + offset_;
1436}
1437
1438template <typename T>
1440{
1441 return data_ + offset_ + size_;
1442}
1443
1444template <typename T>
1446{
1447 return data_;
1448}
1449
1450template <typename T>
1451size_t ConstBufferType<T>::remaining(const size_t tailroom) const
1452{
1453 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1454 return r <= capacity_ ? r : 0;
1455}
1456
1457template <typename T>
1458size_t ConstBufferType<T>::max_size_tailroom(const size_t tailroom) const
1459{
1460 const size_t r = capacity_ - (offset_ + tailroom);
1461 return r <= capacity_ ? r : 0;
1462}
1463
1464template <typename T>
1466{
1467 if (!remaining())
1468 resize(offset_ + size_ + 1);
1469 *(data() + size_++) = value;
1470}
1471
1472template <typename T>
1474{
1475 if (!offset_)
1476 OPENVPN_BUFFER_THROW(buffer_push_front_headroom);
1477 --offset_;
1478 ++size_;
1479 *data() = value;
1480}
1481
1482template <typename T>
1484{
1485 if (!remaining())
1486 resize(offset_ + size_ + 1);
1487 *(data() + size_) = value;
1488}
1489
1490template <typename T>
1492{
1493 if (empty() || back())
1494 push_back(0);
1495}
1496
1497template <typename T>
1498T *ConstBufferType<T>::index(const size_t index)
1499{
1500 if (index >= size_)
1501 OPENVPN_BUFFER_THROW(buffer_index);
1502 return &data()[index];
1503}
1504
1505
1506#ifndef OPENVPN_NO_IO
1507
1508template <typename T>
1509openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer(const size_t tailroom)
1510{
1511 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1512}
1513
1514template <typename T>
1515openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append(const size_t tailroom)
1516{
1517 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1518}
1519
1520template <typename T>
1521openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_clamp(const size_t tailroom)
1522{
1523 return openvpn_io::mutable_buffer(data(), buf_clamp_read(max_size_tailroom(tailroom)));
1524}
1525
1526template <typename T>
1527openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append_clamp(const size_t tailroom)
1528{
1529 return openvpn_io::mutable_buffer(data_end(), buf_clamp_read(remaining(tailroom)));
1530}
1531#endif
1532
1533template <typename T>
1534void ConstBufferType<T>::realign(size_t headroom)
1535{
1536 if (headroom != offset_)
1537 {
1538 if (headroom + size_ > capacity_)
1539 OPENVPN_BUFFER_THROW(buffer_headroom);
1540 std::memmove(data_ + headroom, data_ + offset_, size_);
1541 offset_ = headroom;
1542 }
1543}
1544
1545template <typename T>
1546void ConstBufferType<T>::write(const T *data, const size_t size)
1547{
1548 std::memcpy(write_alloc(size), data, size * sizeof(T));
1549}
1550
1551template <typename T>
1552void ConstBufferType<T>::write(const void *data, const size_t size)
1553{
1554 write((const T *)data, size);
1555}
1556
1557template <typename T>
1558void ConstBufferType<T>::prepend(const T *data, const size_t size)
1559{
1560 std::memcpy(prepend_alloc(size), data, size * sizeof(T));
1561}
1562
1563template <typename T>
1564void ConstBufferType<T>::prepend(const void *data, const size_t size)
1565{
1566 prepend((const T *)data, size);
1567}
1568
1569template <typename T>
1571{
1572 if (size > remaining())
1573 resize(offset_ + size_ + size);
1574 T *ret = data() + size_;
1575 size_ += size;
1576 return ret;
1577}
1578
1579template <typename T>
1580T *ConstBufferType<T>::prepend_alloc(const size_t request_size)
1581{
1582 if (request_size > offset())
1583 realign(request_size);
1584
1585 offset_ -= request_size;
1586 size_ += request_size;
1587
1588 return data();
1589}
1590
1591template <typename T>
1592void ConstBufferType<T>::reset(const size_t min_capacity, const unsigned int flags)
1593{
1594 if (min_capacity > capacity_)
1595 reset_impl(min_capacity, flags);
1596}
1597
1598template <typename T>
1599void ConstBufferType<T>::reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
1600{
1601 reset(min_capacity, flags);
1602 init_headroom(headroom);
1603}
1604
1605template <typename T>
1606template <typename B>
1607void ConstBufferType<T>::append(const B &other)
1608{
1609 write(other.c_data(), other.size());
1610}
1611
1612template <typename T>
1613void ConstBufferType<T>::reset_impl(const size_t min_capacity, const unsigned int flags)
1614{
1615 OPENVPN_BUFFER_THROW(buffer_no_reset_impl);
1616}
1617
1618template <typename T>
1619void ConstBufferType<T>::resize(const size_t new_capacity)
1620{
1621 if (new_capacity > capacity_)
1622 buffer_full_error(new_capacity, false);
1623}
1624
1625template <typename T>
1626void ConstBufferType<T>::buffer_full_error(const size_t newcap, const bool allocated) const
1627{
1628#ifdef OPENVPN_BUFFER_ABORT
1629 std::abort();
1630#else
1631 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));
1632#endif
1633}
1634
1635template <typename T>
1636ConstBufferType<T>::ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
1637 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1638
1639template <typename T>
1640template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1641ConstBufferType<T>::ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
1642 : ConstBufferType(const_cast<U *>(data), offset, size, capacity){};
1643
1644// ===============================================================================================
1645// BufferAllocatedType<T> member function definitions
1646// ===============================================================================================
1647
1648template <typename T>
1649BufferAllocatedType<T>::BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const unsigned int flags)
1650 : BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(flags)
1651{
1653 std::memset(data_raw(), 0, capacity * sizeof(T));
1654}
1655
1656template <typename T>
1658 : BufferAllocatedType(0, 0, 0, 0)
1659{
1660 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1661 "class BufferAllocatedType not noexcept move constructable");
1662}
1663
1664template <typename T>
1665BufferAllocatedType<T>::BufferAllocatedType(const size_t capacity, const unsigned int flags)
1666 : BufferAllocatedType(0, flags & BufAllocFlags::ARRAY ? capacity : 0, capacity, flags){};
1667
1668template <typename T>
1669BufferAllocatedType<T>::BufferAllocatedType(const T *data, const size_t size, const unsigned int flags)
1670 : BufferAllocatedType(0, size, size, flags)
1671{
1672 if (size && data)
1673 std::memcpy(data_raw(), data, size * sizeof(T));
1674}
1675
1676template <typename T>
1678 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), other.flags_)
1679{
1680 if (size())
1681 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1682}
1683
1684template <typename T>
1685template <typename T_>
1687 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), flags)
1688{
1689 static_assert(sizeof(T) == sizeof(T_), "size inconsistency");
1690 if (size())
1691 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1692}
1693
1694template <typename T>
1696{
1697 if (this != &other)
1698 {
1699 auto tempBuffer = BufferAllocatedType(other.offset(), other.size(), other.capacity(), other.flags_);
1700 if (other.size())
1701 std::memcpy(tempBuffer.data(), other.c_data(), tempBuffer.size() * sizeof(T));
1702 swap(tempBuffer);
1703 }
1704}
1705
1706template <typename T>
1707void BufferAllocatedType<T>::init(const size_t capacity, const unsigned int flags)
1708{
1709 auto tempBuffer = BufferAllocatedType(capacity, flags);
1710 swap(tempBuffer);
1711}
1712
1713template <typename T>
1714void BufferAllocatedType<T>::init(const T *data, const size_t size, const unsigned int flags)
1715{
1716 auto tempBuffer = BufferAllocatedType(data, size, flags);
1717 swap(tempBuffer);
1718}
1719
1720template <typename T>
1721void BufferAllocatedType<T>::realloc(const size_t newcap)
1722{
1723 if (newcap > capacity())
1724 realloc_(newcap, offset());
1725}
1726
1727template <typename T>
1729{
1730 if (headroom != offset())
1731 {
1732 if (headroom + size() > capacity())
1733 realloc_(headroom + size(), headroom);
1734 else
1735 BufferType<T>::realign(headroom);
1736 }
1737 return *this;
1738}
1739
1740template <typename T>
1741void BufferAllocatedType<T>::reset(const size_t min_capacity, const unsigned int flags)
1742{
1743 if (min_capacity > capacity())
1744 init(min_capacity, flags);
1745}
1746
1747template <typename T>
1748void BufferAllocatedType<T>::reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
1749{
1750 reset(min_capacity, flags);
1751 init_headroom(headroom);
1752}
1753
1754template <typename T>
1755template <typename T_>
1757{
1758 auto temp = BufferAllocatedType();
1759 swap(other);
1760 other.swap(temp);
1761}
1762
1763template <typename T>
1764template <typename T_>
1766{
1767 BufferType<T>::swap(other);
1768 std::swap(flags_, other.flags_);
1769}
1770
1771template <typename T>
1772template <typename T_>
1775{
1776 move(other);
1777}
1778
1779template <typename T>
1781{
1782 if (this != &other)
1783 {
1784 move(other);
1785 }
1786 return *this;
1787}
1788
1789template <typename T>
1791{
1792 auto tempBuffer = BufferAllocatedType(0, 0, 0, 0);
1793 swap(tempBuffer);
1794}
1795
1796template <typename T>
1798{
1799 flags_ |= flags;
1800}
1801
1802template <typename T>
1804{
1805 flags_ &= flags;
1806}
1807
1808template <typename T>
1810{
1811 if (data_raw())
1812 free_data();
1813}
1814
1815template <typename T>
1816void BufferAllocatedType<T>::reset_impl(const size_t min_capacity, const unsigned int flags)
1817{
1818 init(min_capacity, flags);
1819}
1820
1821template <typename T>
1822void BufferAllocatedType<T>::resize(const size_t new_capacity)
1823{
1824 const size_t newcap = std::max(new_capacity, capacity() * 2);
1825 if (newcap > capacity())
1826 {
1827 if (flags_ & BufAllocFlags::GROW)
1828 realloc_(newcap, offset());
1829 else
1830 buffer_full_error(newcap, true);
1831 }
1832}
1833
1834template <typename T>
1835void BufferAllocatedType<T>::realloc_(const size_t newcap, size_t new_offset)
1836{
1837 auto tempBuffer = BufferAllocatedType(new_offset, size(), newcap, flags_);
1838 if (size())
1839 std::memcpy(tempBuffer.data(), c_data(), size() * sizeof(T));
1840 swap(tempBuffer);
1841}
1842
1843template <typename T>
1845{
1846 if (size() && (flags_ & BufAllocFlags::DESTRUCT_ZERO))
1847 std::memset(data_raw(), 0, capacity() * sizeof(T));
1848 delete[] data_raw();
1849}
1850
1851// ===============================================================================================
1852// specializations of BufferType for unsigned char
1853// ===============================================================================================
1854
1860
1861// ===============================================================================================
1862// BufferAllocated + RC with thread-safe refcount
1863// ===============================================================================================
1864
1867
1868// ===============================================================================================
1869// cast BufferType<T> to ConstBufferType<T>
1870// ===============================================================================================
1871
1872template <typename T>
1874{
1875 return src;
1876}
1877
1878template <typename T>
1880{
1881 return src;
1882}
1883
1884} // namespace openvpn
#define OPENVPN_BUFFER_THROW(exc)
Definition buffer.hpp:64
friend class BufferAllocatedType
Definition buffer.hpp:883
void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
Resets the buffer with the specified headroom, minimum capacity, and flags.
Definition buffer.hpp:1748
BufferAllocatedType(const size_t capacity, const unsigned int flags)
Constructs a BufferAllocatedType with the specified capacity and flags.
Definition buffer.hpp:1665
void clear()
Clears the contents of the buffer.
Definition buffer.hpp:1790
void and_flags(const unsigned int flags)
Clears the specified flags for the buffer.
Definition buffer.hpp:1803
BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const unsigned int flags)
Private constructor.
Definition buffer.hpp:1649
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
Definition buffer.hpp:1780
void init(const size_t capacity, const unsigned int flags)
Initializes the buffer with the specified capacity and flags.
Definition buffer.hpp:1707
BufferAllocatedType(const T *data, const size_t size, const unsigned int flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
Definition buffer.hpp:1669
~BufferAllocatedType()
Destructor.
Definition buffer.hpp:1809
void reset(const size_t min_capacity, const unsigned int flags)
Resets the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1741
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
Definition buffer.hpp:1822
void or_flags(const unsigned int flags)
Sets the specified flags for the buffer.
Definition buffer.hpp:1797
void move(BufferAllocatedType< T_ > &other)
Moves the contents of another BufferAllocatedType object into this object.
Definition buffer.hpp:1756
BufferAllocatedType()
Default constructor.
Definition buffer.hpp:1657
void realloc(const size_t newcap)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1721
void operator=(const BufferAllocatedType &other)
Assignment operator.
Definition buffer.hpp:1695
void reset_impl(const size_t min_capacity, const unsigned int flags) override
Resets the buffer implementation with the specified minimum capacity and flags.
Definition buffer.hpp:1816
void realloc_(const size_t newcap, size_t new_offset)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1835
BufferAllocatedType & realign(const size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1728
void free_data()
Frees the data associated with the buffer.
Definition buffer.hpp:1844
void swap(BufferAllocatedType< T_ > &other)
Swaps the contents of this BufferAllocatedType object with another BufferAllocatedType object.
Definition buffer.hpp:1765
BufferAllocatedType(const BufferAllocatedType &other)
Copy constructor.
Definition buffer.hpp:1677
BufferAllocatedType(const BufferType< T_ > &other, const unsigned int flags)
Constructs a BufferAllocatedType from a BufferType object with the specified flags.
Definition buffer.hpp:1686
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
Definition buffer.hpp:1773
void init(const T *data, const size_t size, const unsigned int flags)
Initializes the buffer with the specified data, size, and flags.
Definition buffer.hpp:1714
report various types of exceptions or errors that may occur when working with buffers
Definition buffer.hpp:114
const char * what() const noexcept override
Definition buffer.hpp:143
virtual ~BufferException() noexcept=default
BufferException(Status status)
Definition buffer.hpp:132
Status status() const
Definition buffer.hpp:151
BufferException(Status status, const std::string &msg)
Definition buffer.hpp:137
static const char * status_string(const Status status)
Definition buffer.hpp:158
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:857
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:846
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:837
Immutable buffer with double ended access and adjustable free space at both ends.
Definition buffer.hpp:229
bool defined() const
Returns true if the buffer is not empty.
Definition buffer.hpp:1207
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:1483
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1177
T * prepend_alloc(const size_t size)
Allocate space for prepending data to the buffer.
Definition buffer.hpp:1580
ConstBufferType(void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a void pointer and size.
Definition buffer.hpp:1094
T * data_end()
Get a mutable pointer to the end of the array.
Definition buffer.hpp:1439
void append(const B &other)
Append data from another buffer to this buffer.
Definition buffer.hpp:1607
void init_headroom(const size_t headroom)
Initializes the headroom (offset) of the buffer.
Definition buffer.hpp:1134
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:1375
size_t length() const
Returns the length of the buffer.
Definition buffer.hpp:1171
std::remove_const_t< T > NCT
Definition buffer.hpp:234
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:1509
size_t max_size() const
Return the maximum allowable size value in T objects given the current offset (without considering re...
Definition buffer.hpp:1360
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:1307
T front() const
Returns the first element of the buffer.
Definition buffer.hpp:1248
ConstBufferType()
Default constructor for ConstBufferType.
Definition buffer.hpp:1085
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
Definition buffer.hpp:1295
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
Definition buffer.hpp:1465
T back() const
Returns the last element of the buffer.
Definition buffer.hpp:1254
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:1111
openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer_append().
Definition buffer.hpp:1527
ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object.
Definition buffer.hpp:1636
void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
Reset the buffer with the specified headroom, minimum capacity, and flags.
Definition buffer.hpp:1599
bool operator!=(const ConstBufferType &other) const
Inequality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1420
ConstBufferType(T *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a pointer to T and size.
Definition buffer.hpp:1103
void write(const void *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1552
ConstBufferType range(size_t offset, size_t len) const
Get a range of the buffer as a ConstBufferType object.
Definition buffer.hpp:1381
void read(void *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1320
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:1641
const T * c_str() const
Returns a const pointer to the null-terminated string representation of the buffer.
Definition buffer.hpp:1165
T * write_alloc(const size_t size)
Allocate space for writing data to the buffer.
Definition buffer.hpp:1570
void reserve(const size_t n)
Reserve additional memory for the buffer.
Definition buffer.hpp:1426
const T * c_data_end() const
Returns a const pointer to the end of the buffer.
Definition buffer.hpp:1183
auto read_alloc_buf(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1345
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1558
bool allocated() const
Returns true if the data memory is defined (allocated).
Definition buffer.hpp:1213
size_t capacity() const
Returns the capacity (raw size) of the allocated buffer in T objects.
Definition buffer.hpp:1195
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1225
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1433
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:1099
T pop_back()
Removes and returns the last element from the buffer.
Definition buffer.hpp:1231
openvpn_io::const_buffer const_buffer_clamp() const
Return a clamped version of const_buffer().
Definition buffer.hpp:1301
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1260
const auto & operator[](const size_t index) const
Const indexing operator for ConstBufferType.
Definition buffer.hpp:1115
bool operator==(const ConstBufferType &other) const
Equality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1412
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1219
void prepend(const void *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1564
const T * c_data_raw() const
Returns a const pointer to the start of the raw data in the buffer.
Definition buffer.hpp:1189
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1546
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:1394
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1326
bool is_zeroed() const
Returns true if the buffer is zeroed (all elements are zero).
Definition buffer.hpp:1281
T pop_front()
Removes and returns the first element from the buffer.
Definition buffer.hpp:1239
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:1451
auto & operator[](const size_t index)
Non-const indexing operator for ConstBufferType.
Definition buffer.hpp:1123
T * data_raw()
Get a mutable pointer to the start of the raw data.
Definition buffer.hpp:1445
void swap(ConstBufferType< T_ > &other)
Swap the contents of this buffer with another buffer.
Definition buffer.hpp:1403
size_t offset() const
Returns the current offset (headroom) into the buffer.
Definition buffer.hpp:1201
void buffer_full_error(const size_t newcap, const bool allocated) const
Throw an exception when the buffer is full.
Definition buffer.hpp:1626
void reset_offset(const size_t offset)
Resets the offset of the buffer.
Definition buffer.hpp:1143
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:1498
bool contains_null() const
Returns true if the buffer contains a null character.
Definition buffer.hpp:1269
void push_front(const T &value)
Append a T object to the array, with possible resize.
Definition buffer.hpp:1473
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1367
void reset_content()
Resets the content of the buffer.
Definition buffer.hpp:1159
virtual void resize(const size_t new_capacity)
Derived classes can implement buffer growing semantics by overloading this method....
Definition buffer.hpp:1619
void null_terminate()
Null-terminate the array.
Definition buffer.hpp:1491
void reset_size()
Resets the size of the buffer to zero.
Definition buffer.hpp:1153
void realign(size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1534
openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer().
Definition buffer.hpp:1521
void reset(const size_t min_capacity, const unsigned int flags)
Reset the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1592
virtual void reset_impl(const size_t min_capacity, const unsigned int flags)
Called when the reset method needs to expand the buffer size.
Definition buffer.hpp:1613
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:1515
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:1458
void read(NCT *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1314
A class template that enables reference counting for a given type.
Definition make_rc.hpp:29
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
ConstBufferType< T > & const_buffer_ref(BufferType< T > &src)
Definition buffer.hpp:1873
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
@ DESTRUCT_ZERO
if enabled, destructor will zero data before deletion
Definition buffer.hpp:871
@ ARRAY
if enabled, use as array
Definition buffer.hpp:873
@ GROW
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
Definition buffer.hpp:872
@ CONSTRUCT_ZERO
if enabled, constructors/init will zero allocated space
Definition buffer.hpp:870
reroute_gw flags
std::string ret
#define msg(flags,...)