libtins 4.5
Loading...
Searching...
No Matches
pdu_option.h
1/*
2 * Copyright (c) 2017, Matias Fontanini
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#ifndef TINS_PDU_OPTION_H
31#define TINS_PDU_OPTION_H
32
33#include <vector>
34#include <string>
35#include <cstring>
36#include <stdint.h>
37#include <tins/exceptions.h>
38#include <tins/detail/type_traits.h>
39
40namespace Tins {
41
42class IPv4Address;
43class IPv6Address;
44template <size_t n>
45class HWAddress;
46
50template <typename OptionType, typename PDUType>
51class PDUOption;
52
53namespace Internals {
54 namespace Converters {
55 uint8_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
56 type_to_type<uint8_t>);
57 int8_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
58 type_to_type<int8_t>);
59 uint16_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
60 type_to_type<uint16_t>);
61 uint32_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
62 type_to_type<uint32_t>);
63 uint64_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
64 type_to_type<uint64_t>);
65 HWAddress<6> convert(const uint8_t* ptr, uint32_t data_size,
66 PDU::endian_type endian, type_to_type<HWAddress<6> >);
67 IPv4Address convert(const uint8_t* ptr, uint32_t data_size,
68 PDU::endian_type endian, type_to_type<IPv4Address>);
69 IPv6Address convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian,
70 type_to_type<IPv6Address>);
71 std::string convert(const uint8_t* ptr, uint32_t data_size,
72 PDU::endian_type endian, type_to_type<std::string>);
73 std::vector<float> convert(const uint8_t* ptr, uint32_t data_size,
74 PDU::endian_type endian, type_to_type<std::vector<float> >);
75 std::vector<uint8_t> convert(const uint8_t* ptr, uint32_t data_size,
76 PDU::endian_type endian, type_to_type<std::vector<uint8_t> >);
77 std::vector<uint16_t> convert(const uint8_t* ptr, uint32_t data_size,
78 PDU::endian_type endian,
79 type_to_type<std::vector<uint16_t> >);
80 std::vector<uint32_t> convert(const uint8_t* ptr, uint32_t data_size,
81 PDU::endian_type endian,
82 type_to_type<std::vector<uint32_t> >);
83 std::vector<IPv4Address> convert(const uint8_t* ptr, uint32_t data_size,
84 PDU::endian_type endian,
85 type_to_type<std::vector<IPv4Address> >);
86 std::vector<IPv6Address> convert(const uint8_t* ptr, uint32_t data_size,
87 PDU::endian_type endian,
88 type_to_type<std::vector<IPv6Address> >);
89 std::vector<std::pair<uint8_t, uint8_t> > convert(const uint8_t* ptr, uint32_t data_size,
90 PDU::endian_type endian,
91 type_to_type<std::vector<std::pair<uint8_t, uint8_t> > >);
92 std::pair<uint8_t, uint8_t> convert(const uint8_t* ptr, uint32_t data_size,
93 PDU::endian_type endian,
94 type_to_type<std::pair<uint8_t, uint8_t> >);
95 std::pair<uint16_t, uint32_t> convert(const uint8_t* ptr, uint32_t data_size,
96 PDU::endian_type endian,
97 type_to_type<std::pair<uint16_t, uint32_t> >);
98 std::pair<uint32_t, uint32_t> convert(const uint8_t* ptr, uint32_t data_size,
99 PDU::endian_type endian,
100 type_to_type<std::pair<uint32_t, uint32_t> >);
101 } // Converters
102
103 struct converter {
104 template <typename T, typename X, typename PDUType>
105 static T do_convert(const PDUOption<X, PDUType>& opt, type_to_type<T>) {
106 return T::from_option(opt);
107 }
108
109 template <typename U, typename X, typename PDUType>
110 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<uint8_t> type) {
111 return Converters::convert(opt.data_ptr(), opt.data_size(),
112 PDUType::endianness, type);
113 }
114
115 template <typename U, typename X, typename PDUType>
116 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<int8_t> type) {
117 return Converters::convert(opt.data_ptr(), opt.data_size(),
118 PDUType::endianness, type);
119 }
120
121 template <typename U, typename X, typename PDUType>
122 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<uint16_t> type) {
123 return Converters::convert(opt.data_ptr(), opt.data_size(),
124 PDUType::endianness, type);
125 }
126
127 template <typename U, typename X, typename PDUType>
128 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<uint32_t> type) {
129 return Converters::convert(opt.data_ptr(), opt.data_size(),
130 PDUType::endianness, type);
131 }
132
133 template <typename U, typename X, typename PDUType>
134 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<uint64_t> type) {
135 return Converters::convert(opt.data_ptr(), opt.data_size(),
136 PDUType::endianness, type);
137 }
138
139 template <typename U, typename X, typename PDUType>
140 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<HWAddress<6> > type) {
141 return Converters::convert(opt.data_ptr(), opt.data_size(),
142 PDUType::endianness, type);
143 }
144
145 template <typename U, typename X, typename PDUType>
146 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<IPv4Address> type) {
147 return Converters::convert(opt.data_ptr(), opt.data_size(),
148 PDUType::endianness, type);
149 }
150
151 template <typename U, typename X, typename PDUType>
152 static U do_convert(const PDUOption<X, PDUType>& opt, type_to_type<IPv6Address> type) {
153 return Converters::convert(opt.data_ptr(), opt.data_size(),
154 PDUType::endianness, type);
155 }
156
157 template <typename U, typename X, typename PDUType>
158 static U do_convert(const PDUOption<X, PDUType>& opt,
159 type_to_type<std::string> type) {
160 return Converters::convert(opt.data_ptr(), opt.data_size(),
161 PDUType::endianness, type);
162 }
163
164 template <typename U, typename X, typename PDUType, typename Z>
165 static U do_convert(const PDUOption<X, PDUType>& opt,
166 type_to_type<std::vector<Z> > type) {
167 return Converters::convert(opt.data_ptr(), opt.data_size(),
168 PDUType::endianness, type);
169 }
170
171 template <typename U, typename X, typename PDUType, typename Z, typename W>
172 static U do_convert(const PDUOption<X, PDUType>& opt,
173 type_to_type<std::pair<Z, W> > type) {
174 return Converters::convert(opt.data_ptr(), opt.data_size(),
175 PDUType::endianness, type);
176 }
177
178 template <typename T, typename X, typename PDUType>
179 static T convert(const PDUOption<X, PDUType>& opt) {
180 return do_convert<T>(opt, type_to_type<T>());
181 }
182 };
183}
184
200template <typename OptionType, typename PDUType>
201class PDUOption {
202private:
203 static const int small_buffer_size = 8;
204public:
205 typedef uint8_t data_type;
206 typedef OptionType option_type;
207
214 PDUOption(option_type opt = option_type(),
215 size_t length = 0,
216 const data_type* data = 0)
217 : option_(opt), size_(static_cast<uint16_t>(length)), real_size_(0) {
218 if (data != 0) {
219 set_payload_contents(data, data + length);
220 }
221 }
222
227 PDUOption(const PDUOption& rhs) {
228 real_size_ = 0;
229 *this = rhs;
230 }
231
232 #if TINS_IS_CXX11
237 PDUOption(PDUOption&& rhs) TINS_NOEXCEPT {
238 real_size_ = 0;
239 *this = std::move(rhs);
240 }
241
246 PDUOption& operator=(PDUOption&& rhs) TINS_NOEXCEPT {
247 option_ = rhs.option_;
248 size_ = rhs.size_;
249 if (real_size_ > small_buffer_size) {
250 delete[] payload_.big_buffer_ptr;
251 }
252 real_size_ = rhs.real_size_;
253 if (real_size_ > small_buffer_size) {
254 payload_.big_buffer_ptr = 0;
255 std::swap(payload_.big_buffer_ptr, rhs.payload_.big_buffer_ptr);
256 rhs.real_size_ = 0;
257 }
258 else {
259 std::memcpy(payload_.small_buffer, rhs.data_ptr(), rhs.data_size());
260 }
261 return *this;
262 }
263
264 #endif // TINS_IS_CXX11
265
271 option_ = rhs.option_;
272 size_ = rhs.size_;
273 if (real_size_ > small_buffer_size) {
274 delete[] payload_.big_buffer_ptr;
275 }
276 real_size_ = rhs.real_size_;
277 set_payload_contents(rhs.data_ptr(), rhs.data_ptr() + rhs.data_size());
278 return* this;
279 }
280
285 if (real_size_ > small_buffer_size) {
286 delete[] payload_.big_buffer_ptr;
287 }
288 }
289
298 template<typename ForwardIterator>
299 PDUOption(option_type opt, ForwardIterator start, ForwardIterator end)
300 : option_(opt), size_(static_cast<uint16_t>(std::distance(start, end))) {
301 set_payload_contents(start, end);
302 }
303
319 template<typename ForwardIterator>
320 PDUOption(option_type opt, uint16_t length, ForwardIterator start, ForwardIterator end)
321 : option_(opt), size_(length) {
322 set_payload_contents(start, end);
323 }
324
329 option_type option() const {
330 return option_;
331 }
332
337 void option(option_type opt) {
338 option_ = opt;
339 }
340
350 const data_type* data_ptr() const {
351 return real_size_ <= small_buffer_size ?
352 payload_.small_buffer :
353 payload_.big_buffer_ptr;
354 }
355
361 size_t data_size() const {
362 return real_size_;
363 }
364
377 size_t length_field() const {
378 return size_;
379 }
380
388 template<typename T>
389 T to() const {
390 return Internals::converter::convert<T>(*this);
391 }
392private:
393 template<typename ForwardIterator>
394 void set_payload_contents(ForwardIterator start, ForwardIterator end) {
395 size_t total_size = std::distance(start, end);
396 if (total_size > 65535) {
398 }
399 real_size_ = static_cast<uint16_t>(total_size);
400 if (real_size_ <= small_buffer_size) {
401 if (total_size > 0) {
402 std::memcpy(payload_.small_buffer, &*start, total_size);
403 }
404 }
405 else {
406 payload_.big_buffer_ptr = new data_type[real_size_];
407 uint8_t* ptr = payload_.big_buffer_ptr;
408 while (start < end) {
409 *ptr = *start;
410 ++ptr;
411 ++start;
412 }
413 }
414 }
415
416 option_type option_;
417 uint16_t size_, real_size_;
418 union {
419 data_type small_buffer[small_buffer_size];
420 data_type* big_buffer_ptr;
421 } payload_;
422};
423
424namespace Internals {
425/*
426 * \cond
427 */
428
429template <typename Option, typename Container>
430typename Container::iterator find_option(Container& cont, typename Option::option_type type) {
431 typename Container::iterator iter;
432 for (iter = cont.begin(); iter != cont.end(); ++iter) {
433 if (iter->option() == type) {
434 break;
435 }
436 }
437 return iter;
438}
439
440template <typename Option, typename Container>
441typename Container::const_iterator find_option_const(const Container& cont,
442 typename Option::option_type type) {
443 typename Container::const_iterator iter;
444 for (iter = cont.begin(); iter != cont.end(); ++iter) {
445 if (iter->option() == type) {
446 break;
447 }
448 }
449 return iter;
450}
451
452/*
453 * \endcond
454 */
455} // Internals
456
457} // namespace Tins
458#endif // TINS_PDU_OPTION_H
Represents a PDU option field.
Definition rsn_information.h:43
PDUOption(option_type opt=option_type(), size_t length=0, const data_type *data=0)
Constructs a PDUOption.
Definition pdu_option.h:214
const data_type * data_ptr() const
Definition pdu_option.h:350
T to() const
Constructs a T from this PDUOption.
Definition pdu_option.h:389
PDUOption(PDUOption &&rhs) TINS_NOEXCEPT
Move constructor.
Definition pdu_option.h:237
PDUOption(option_type opt, ForwardIterator start, ForwardIterator end)
Constructs a PDUOption from iterators, which indicate the data to be stored in it.
Definition pdu_option.h:299
PDUOption & operator=(const PDUOption &rhs)
Copy assignment operator.
Definition pdu_option.h:270
size_t length_field() const
Retrieves the data length field.
Definition pdu_option.h:377
~PDUOption()
Destructor.
Definition pdu_option.h:284
size_t data_size() const
Retrieves the length of this option's data.
Definition pdu_option.h:361
void option(option_type opt)
Definition pdu_option.h:337
PDUOption & operator=(PDUOption &&rhs) TINS_NOEXCEPT
Move assignment operator.
Definition pdu_option.h:246
option_type option() const
Definition pdu_option.h:329
PDUOption(option_type opt, uint16_t length, ForwardIterator start, ForwardIterator end)
Constructs a PDUOption from iterators, which indicate the data to be stored in it.
Definition pdu_option.h:320
PDUOption(const PDUOption &rhs)
Copy constructor.
Definition pdu_option.h:227
endian_type
Definition pdu.h:117
Exception thrown when a payload is too large to fit into a PDUOption.
Definition exceptions.h:220
The Tins namespace.
Definition address_range.h:38