Kea 2.2.0
option_custom.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8#include <dhcp/libdhcp++.h>
10#include <dhcp/option_custom.h>
12#include <util/encode/hex.h>
13
14using namespace isc::asiolink;
15
16namespace isc {
17namespace dhcp {
18
20 Universe u)
21 : Option(u, def.getCode(), OptionBuffer()),
22 definition_(def) {
24 createBuffers();
25}
26
28 Universe u,
29 const OptionBuffer& data)
30 : Option(u, def.getCode(), data.begin(), data.end()),
31 definition_(def) {
33 createBuffers(getData());
34}
35
37 Universe u,
40 : Option(u, def.getCode(), first, last),
41 definition_(def) {
43 createBuffers(getData());
44}
45
48 return (cloneInternal<OptionCustom>());
49}
50
51void
53 checkArrayType();
54
55 if ((address.isV4() && definition_.getType() != OPT_IPV4_ADDRESS_TYPE) ||
56 (address.isV6() && definition_.getType() != OPT_IPV6_ADDRESS_TYPE)) {
57 isc_throw(BadDataTypeCast, "invalid address specified "
58 << address << ". Expected a valid IPv"
59 << (definition_.getType() == OPT_IPV4_ADDRESS_TYPE ?
60 "4" : "6") << " address.");
61 }
62
63 OptionBuffer buf;
65 buffers_.push_back(buf);
66}
67
68void
69OptionCustom::addArrayDataField(const std::string& value) {
70 checkArrayType();
71
74 OptionBuffer buf;
75 OptionDataTypeUtil::writeTuple(value, lft, buf);
76 buffers_.push_back(buf);
77}
78
79void
81 checkArrayType();
82
83 OptionBuffer buf;
85 buffers_.push_back(buf);
86}
87
88void
90 checkArrayType();
91
92 OptionBuffer buf;
94 buffers_.push_back(buf);
95}
96
97void
99 const asiolink::IOAddress& prefix) {
100 checkArrayType();
101
102 if (definition_.getType() != OPT_IPV6_PREFIX_TYPE) {
103 isc_throw(BadDataTypeCast, "IPv6 prefix can be specified only for"
104 " an option comprising an array of IPv6 prefix values");
105 }
106
107 OptionBuffer buf;
108 OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
109 buffers_.push_back(buf);
110}
111
112void
113OptionCustom::addArrayDataField(const PSIDLen& psid_len, const PSID& psid) {
114 checkArrayType();
115
116 if (definition_.getType() != OPT_PSID_TYPE) {
117 isc_throw(BadDataTypeCast, "PSID value can be specified onlu for"
118 " an option comprising an array of PSID length / value"
119 " tuples");
120 }
121
122 OptionBuffer buf;
123 OptionDataTypeUtil::writePsid(psid_len, psid, buf);
124 buffers_.push_back(buf);
125}
126
127void
128OptionCustom::checkIndex(const uint32_t index) const {
129 if (index >= buffers_.size()) {
130 isc_throw(isc::OutOfRange, "specified data field index " << index
131 << " is out of range.");
132 }
133}
134
135void
136OptionCustom::createBuffer(OptionBuffer& buffer,
137 const OptionDataType data_type) const {
138 // For data types that have a fixed size we can use the
139 // utility function to get the buffer's size.
140 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
141
142 // For variable data sizes the utility function returns zero.
143 // It is ok for string values because the default string
144 // is 'empty'. However for FQDN the empty value is not valid
145 // so we initialize it to '.'. For prefix there is a prefix
146 // length fixed field.
147 if (data_size == 0) {
148 if (data_type == OPT_FQDN_TYPE) {
150
151 } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
154 buffer);
155 }
156 } else {
157 // At this point we can resize the buffer. Note that
158 // for string values we are setting the empty buffer
159 // here.
160 buffer.resize(data_size);
161 }
162}
163
164void
165OptionCustom::createBuffers() {
166 definition_.validate();
167
168 std::vector<OptionBuffer> buffers;
169
170 OptionDataType data_type = definition_.getType();
171 // This function is called when an empty data buffer has been
172 // passed to the constructor. In such cases values for particular
173 // data fields will be set using modifier functions but for now
174 // we need to initialize a set of buffers that are specified
175 // for an option by its definition. Since there is no data yet,
176 // we are going to fill these buffers with default values.
177 if (data_type == OPT_RECORD_TYPE) {
178 // For record types we need to iterate over all data fields
179 // specified in option definition and create corresponding
180 // buffers for each of them.
182 definition_.getRecordFields();
183
184 for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
185 field != fields.end(); ++field) {
186 OptionBuffer buf;
187 createBuffer(buf, *field);
188 // We have the buffer with default value prepared so we
189 // add it to the set of buffers.
190 buffers.push_back(buf);
191 }
192 } else if (!definition_.getArrayType() &&
193 data_type != OPT_EMPTY_TYPE) {
194 // For either 'empty' options we don't have to create any buffers
195 // for obvious reason. For arrays we also don't create any buffers
196 // yet because the set of fields that belong to the array is open
197 // ended so we can't allocate required buffers until we know how
198 // many of them are needed.
199 // For non-arrays we have a single value being held by the option
200 // so we have to allocate exactly one buffer.
201 OptionBuffer buf;
202 createBuffer(buf, data_type);
203 // Add a buffer that we have created and leave.
204 buffers.push_back(buf);
205 }
206 // The 'swap' is used here because we want to make sure that we
207 // don't touch buffers_ until we successfully allocate all
208 // buffers to be stored there.
209 std::swap(buffers, buffers_);
210}
211
212size_t
213OptionCustom::bufferLength(const OptionDataType data_type, bool in_array,
214 OptionBuffer::const_iterator begin,
215 OptionBuffer::const_iterator end) const {
216 // For fixed-size data type such as boolean, integer, even
217 // IP address we can use the utility function to get the required
218 // buffer size.
219 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
220
221 // For variable size types (e.g. string) the function above will
222 // return 0 so we need to do a runtime check of the length.
223 if (data_size == 0) {
224 // FQDN is a special data type as it stores variable length data
225 // but the data length is encoded in the buffer. The easiest way
226 // to obtain the length of the data is to read the FQDN. The
227 // utility function will return the size of the buffer on success.
228 if (data_type == OPT_FQDN_TYPE) {
229 std::string fqdn =
231 // The size of the buffer holding an FQDN is always
232 // 1 byte larger than the size of the string
233 // representation of this FQDN.
234 data_size = fqdn.size() + 1;
235 } else if (!definition_.getArrayType() &&
236 ((data_type == OPT_BINARY_TYPE) ||
237 (data_type == OPT_STRING_TYPE))) {
238 // In other case we are dealing with string or binary value
239 // which size can't be determined. Thus we consume the
240 // remaining part of the buffer for it. Note that variable
241 // size data can be laid at the end of the option only and
242 // that the validate() function in OptionDefinition object
243 // should have checked wheter it is a case for this option.
244 data_size = std::distance(begin, end);
245 } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
246 // The size of the IPV6 prefix type is determined as
247 // one byte (which is the size of the prefix in bits)
248 // followed by the prefix bits (right-padded with
249 // zeros to the nearest octet boundary)
250 if ((begin == end) && !in_array)
251 return 0;
252 PrefixTuple prefix =
254 // Data size comprises 1 byte holding a prefix length and the
255 // prefix length (in bytes) rounded to the nearest byte boundary.
256 data_size = sizeof(uint8_t) + (prefix.first.asUint8() + 7) / 8;
257 } else if (data_type == OPT_TUPLE_TYPE) {
262 std::string value =
264 data_size = value.size();
265 // The size of the buffer holding a tuple is always
266 // 1 or 2 byte larger than the size of the string
267 data_size += getUniverse() == Option::V4 ? 1 : 2;
268 } else {
269 // If we reached the end of buffer we assume that this option is
270 // truncated because there is no remaining data to initialize
271 // an option field.
272 isc_throw(OutOfRange, "option buffer truncated");
273 }
274 }
275
276 return data_size;
277}
278
279void
280OptionCustom::createBuffers(const OptionBuffer& data_buf) {
281 // Check that the option definition is correct as we are going
282 // to use it to split the data_ buffer into set of sub buffers.
283 definition_.validate();
284
285 std::vector<OptionBuffer> buffers;
286 OptionBuffer::const_iterator data = data_buf.begin();
287
288 OptionDataType data_type = definition_.getType();
289 if (data_type == OPT_RECORD_TYPE) {
290 // An option comprises a record of data fields. We need to
291 // get types of these data fields to allocate enough space
292 // for each buffer.
294 definition_.getRecordFields();
295
296 // Go over all data fields within a record.
297 for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
298 field != fields.end(); ++field) {
299 size_t data_size = bufferLength(*field, false,
300 data, data_buf.end());
301
302 // Our data field requires that there is a certain chunk of
303 // data left in the buffer. If not, option is truncated.
304 if (std::distance(data, data_buf.end()) < data_size) {
305 isc_throw(OutOfRange, "option buffer truncated");
306 }
307
308 // Store the created buffer.
309 buffers.push_back(OptionBuffer(data, data + data_size));
310 // Proceed to the next data field.
311 data += data_size;
312 }
313
314 // Get extra buffers when the last field is an array.
315 if (definition_.getArrayType()) {
316 while (data != data_buf.end()) {
317 // Code copied from the standard array case
318 size_t data_size = bufferLength(fields.back(), true,
319 data, data_buf.end());
320 isc_throw_assert(data_size > 0);
321 if (std::distance(data, data_buf.end()) < data_size) {
322 break;
323 }
324 buffers.push_back(OptionBuffer(data, data + data_size));
325 data += data_size;
326 }
327 }
328
329 // Unpack suboptions if any.
330 else if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
331 unpackOptions(OptionBuffer(data, data_buf.end()));
332 }
333
334 } else if (data_type != OPT_EMPTY_TYPE) {
335 // If data_type value is other than OPT_RECORD_TYPE, our option is
336 // empty (have no data at all) or it comprises one or more
337 // data fields of the same type. The type of those fields
338 // is held in the data_type variable so let's use it to determine
339 // a size of buffers.
340 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
341 // The check below will fail if the input buffer is too short
342 // for the data size being held by this option.
343 // Note that data_size returned by getDataTypeLen may be zero
344 // if variable length data is being held by the option but
345 // this will not cause this check to throw exception.
346 if (std::distance(data, data_buf.end()) < data_size) {
347 isc_throw(OutOfRange, "option buffer truncated");
348 }
349 // For an array of values we are taking different path because
350 // we have to handle multiple buffers.
351 if (definition_.getArrayType()) {
352 while (data != data_buf.end()) {
353 data_size = bufferLength(data_type, true, data, data_buf.end());
354 // We don't perform other checks for data types that can't be
355 // used together with array indicator such as strings, empty field
356 // etc. This is because OptionDefinition::validate function should
357 // have checked this already. Thus data_size must be greater than
358 // zero.
359 isc_throw_assert(data_size > 0);
360 // Get chunks of data and store as a collection of buffers.
361 // Truncate any remaining part which length is not divisible by
362 // data_size. Note that it is ok to truncate the data if and only
363 // if the data buffer is long enough to keep at least one value.
364 // This has been checked above already.
365 if (std::distance(data, data_buf.end()) < data_size) {
366 break;
367 }
368 buffers.push_back(OptionBuffer(data, data + data_size));
369 data += data_size;
370 }
371 } else {
372 // For non-arrays the data_size can be zero because
373 // getDataTypeLen returns zero for variable size data types
374 // such as strings. Simply take whole buffer.
375 data_size = bufferLength(data_type, false, data, data_buf.end());
376 if ((data_size > 0) && (std::distance(data, data_buf.end()) >= data_size)) {
377 buffers.push_back(OptionBuffer(data, data + data_size));
378 data += data_size;
379 } else {
380 isc_throw(OutOfRange, "option buffer truncated");
381 }
382
383 // Unpack suboptions if any.
384 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
385 unpackOptions(OptionBuffer(data, data_buf.end()));
386 }
387 }
388 } else {
389 // Unpack suboptions if any.
390 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
391 unpackOptions(OptionBuffer(data, data_buf.end()));
392 }
393 }
394 // If everything went ok we can replace old buffer set with new ones.
395 std::swap(buffers_, buffers);
396}
397
398std::string
399OptionCustom::dataFieldToText(const OptionDataType data_type,
400 const uint32_t index) const {
401 std::ostringstream text;
402
403 // Get the value of the data field.
404 switch (data_type) {
405 case OPT_BINARY_TYPE:
406 text << util::encode::encodeHex(readBinary(index));
407 break;
408 case OPT_BOOLEAN_TYPE:
409 text << (readBoolean(index) ? "true" : "false");
410 break;
411 case OPT_INT8_TYPE:
412 text << static_cast<int>(readInteger<int8_t>(index));
413 break;
414 case OPT_INT16_TYPE:
415 text << readInteger<int16_t>(index);
416 break;
417 case OPT_INT32_TYPE:
418 text << readInteger<int32_t>(index);
419 break;
420 case OPT_UINT8_TYPE:
421 text << static_cast<unsigned>(readInteger<uint8_t>(index));
422 break;
423 case OPT_UINT16_TYPE:
424 text << readInteger<uint16_t>(index);
425 break;
426 case OPT_UINT32_TYPE:
427 text << readInteger<uint32_t>(index);
428 break;
431 text << readAddress(index);
432 break;
433 case OPT_FQDN_TYPE:
434 text << "\"" << readFqdn(index) << "\"";
435 break;
436 case OPT_TUPLE_TYPE:
437 text << "\"" << readTuple(index) << "\"";
438 break;
439 case OPT_STRING_TYPE:
440 text << "\"" << readString(index) << "\"";
441 break;
442 case OPT_PSID_TYPE:
443 {
444 PSIDTuple t = readPsid(index);
445 text << "len=" << t.first.asUnsigned() << ",psid=" << t.second.asUint16();
446 }
447 default:
448 ;
449 }
450
451 // Append data field type in brackets.
452 text << " (" << OptionDataTypeUtil::getDataTypeName(data_type) << ")";
453
454 return (text.str());
455}
456
457void
459
460 // Pack DHCP header (V4 or V6).
461 packHeader(buf, check);
462
463 // Write data from buffers.
464 for (std::vector<OptionBuffer>::const_iterator it = buffers_.begin();
465 it != buffers_.end(); ++it) {
466 // In theory the createBuffers function should have taken
467 // care that there are no empty buffers added to the
468 // collection but it is almost always good to make sure.
469 if (!it->empty()) {
470 buf.writeData(&(*it)[0], it->size());
471 }
472 }
473
474 // Write suboptions.
475 packOptions(buf, check);
476}
477
478
480OptionCustom::readAddress(const uint32_t index) const {
481 checkIndex(index);
482
483 // The address being read can be either IPv4 or IPv6. The decision
484 // is made based on the buffer length. If it holds 4 bytes it is IPv4
485 // address, if it holds 16 bytes it is IPv6.
486 if (buffers_[index].size() == asiolink::V4ADDRESS_LEN) {
487 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET));
488 } else if (buffers_[index].size() == asiolink::V6ADDRESS_LEN) {
489 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET6));
490 } else {
491 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
492 << " IP address. Invalid buffer length "
493 << buffers_[index].size() << ".");
494 }
495}
496
497void
499 const uint32_t index) {
500 checkIndex(index);
501
502 if ((address.isV4() && buffers_[index].size() != V4ADDRESS_LEN) ||
503 (address.isV6() && buffers_[index].size() != V6ADDRESS_LEN)) {
504 isc_throw(BadDataTypeCast, "invalid address specified "
505 << address << ". Expected a valid IPv"
506 << (buffers_[index].size() == V4ADDRESS_LEN ? "4" : "6")
507 << " address.");
508 }
509
510 OptionBuffer buf;
512 std::swap(buf, buffers_[index]);
513}
514
515const OptionBuffer&
516OptionCustom::readBinary(const uint32_t index) const {
517 checkIndex(index);
518 return (buffers_[index]);
519}
520
521void
523 const uint32_t index) {
524 checkIndex(index);
525 buffers_[index] = buf;
526}
527
528std::string
529OptionCustom::readTuple(const uint32_t index) const {
530 checkIndex(index);
533 return (OptionDataTypeUtil::readTuple(buffers_[index], lft));
534}
535
536void
538 const uint32_t index) const {
539 checkIndex(index);
540 OptionDataTypeUtil::readTuple(buffers_[index], tuple);
541}
542
543void
544OptionCustom::writeTuple(const std::string& value, const uint32_t index) {
545 checkIndex(index);
546
547 buffers_[index].clear();
550 OptionDataTypeUtil::writeTuple(value, lft, buffers_[index]);
551}
552
553void
554OptionCustom::writeTuple(const OpaqueDataTuple& value, const uint32_t index) {
555 checkIndex(index);
556
557 buffers_[index].clear();
558 OptionDataTypeUtil::writeTuple(value, buffers_[index]);
559}
560
561bool
562OptionCustom::readBoolean(const uint32_t index) const {
563 checkIndex(index);
564 return (OptionDataTypeUtil::readBool(buffers_[index]));
565}
566
567void
568OptionCustom::writeBoolean(const bool value, const uint32_t index) {
569 checkIndex(index);
570
571 buffers_[index].clear();
572 OptionDataTypeUtil::writeBool(value, buffers_[index]);
573}
574
575std::string
576OptionCustom::readFqdn(const uint32_t index) const {
577 checkIndex(index);
578 return (OptionDataTypeUtil::readFqdn(buffers_[index]));
579}
580
581void
582OptionCustom::writeFqdn(const std::string& fqdn, const uint32_t index) {
583 checkIndex(index);
584
585 // Create a temporary buffer where the FQDN will be written.
586 OptionBuffer buf;
587 // Try to write to the temporary buffer rather than to the
588 // buffers_ member directly guarantees that we don't modify
589 // (clear) buffers_ until we are sure that the provided FQDN
590 // is valid.
592 // If we got to this point it means that the FQDN is valid.
593 // We can move the contents of the temporary buffer to the
594 // target buffer.
595 std::swap(buffers_[index], buf);
596}
597
599OptionCustom::readPrefix(const uint32_t index) const {
600 checkIndex(index);
601 return (OptionDataTypeUtil::readPrefix(buffers_[index]));
602}
603
604void
606 const IOAddress& prefix,
607 const uint32_t index) {
608 checkIndex(index);
609
610 OptionBuffer buf;
611 OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
612 // If there are no errors while writing PSID to a buffer, we can
613 // replace the current buffer with a new buffer.
614 std::swap(buffers_[index], buf);
615}
616
617
619OptionCustom::readPsid(const uint32_t index) const {
620 checkIndex(index);
621 return (OptionDataTypeUtil::readPsid(buffers_[index]));
622}
623
624void
625OptionCustom::writePsid(const PSIDLen& psid_len, const PSID& psid,
626 const uint32_t index) {
627 checkIndex(index);
628
629 OptionBuffer buf;
630 OptionDataTypeUtil::writePsid(psid_len, psid, buf);
631 // If there are no errors while writing PSID to a buffer, we can
632 // replace the current buffer with a new buffer.
633 std::swap(buffers_[index], buf);
634}
635
636
637std::string
638OptionCustom::readString(const uint32_t index) const {
639 checkIndex(index);
640 return (OptionDataTypeUtil::readString(buffers_[index]));
641}
642
643void
644OptionCustom::writeString(const std::string& text, const uint32_t index) {
645 checkIndex(index);
646
647 // Let's clear a buffer as we want to replace the value of the
648 // whole buffer. If we fail to clear the buffer the data will
649 // be appended.
650 buffers_[index].clear();
651 // If the text value is empty we can leave because the buffer
652 // is already empty.
653 if (!text.empty()) {
654 OptionDataTypeUtil::writeString(text, buffers_[index]);
655 }
656}
657
658void
661 initialize(begin, end);
662}
663
664uint16_t
666 // The length of the option is a sum of option header ...
667 size_t length = getHeaderLen();
668
669 // ... lengths of all buffers that hold option data ...
670 for (std::vector<OptionBuffer>::const_iterator buf = buffers_.begin();
671 buf != buffers_.end(); ++buf) {
672 length += buf->size();
673 }
674
675 // ... and lengths of all suboptions
676 for (OptionCollection::const_iterator it = options_.begin();
677 it != options_.end();
678 ++it) {
679 length += (*it).second->len();
680 }
681
682 return (static_cast<uint16_t>(length));
683}
684
686 const OptionBufferConstIter last) {
687 setData(first, last);
688
689 // Chop the data_ buffer into set of buffers that represent
690 // option fields data.
691 createBuffers(getData());
692}
693
694std::string OptionCustom::toText(int indent) const {
695 std::stringstream output;
696
697 output << headerToText(indent) << ":";
698
699 OptionDataType data_type = definition_.getType();
700 if (data_type == OPT_RECORD_TYPE) {
702 definition_.getRecordFields();
703
704 // For record types we iterate over fields defined in
705 // option definition and match the appropriate buffer
706 // with them.
707 for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
708 field != fields.end(); ++field) {
709 output << " " << dataFieldToText(*field, std::distance(fields.begin(),
710 field));
711 }
712
713 // If the last record field is an array iterate on extra buffers
714 if (definition_.getArrayType()) {
715 for (unsigned int i = fields.size(); i < getDataFieldsNum(); ++i) {
716 output << " " << dataFieldToText(fields.back(), i);
717 }
718 }
719 } else {
720 // For non-record types we iterate over all buffers
721 // and print the data type set globally for an option
722 // definition. We take the same code path for arrays
723 // and non-arrays as they only differ in such a way that
724 // non-arrays have just single data field.
725 for (unsigned int i = 0; i < getDataFieldsNum(); ++i) {
726 output << " " << dataFieldToText(definition_.getType(), i);
727 }
728 }
729
730 // Append suboptions.
731 output << suboptionsToText(indent + 2);
732
733 return (output.str());
734}
735
736} // end of isc::dhcp namespace
737} // end of isc namespace
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Exception to be thrown when cast to the data type was unsuccessful.
Represents a single instance of the opaque data preceded by length.
LengthFieldType
Size of the length field in the tuple.
std::string readString(const uint32_t index=0) const
Read a buffer as string value.
bool readBoolean(const uint32_t index=0) const
Read a buffer as boolean value.
virtual uint16_t len() const
Returns length of the complete option (data length + DHCPv4/DHCPv6 option header)
std::string readTuple(const uint32_t index=0) const
Read a buffer as length and string tuple.
void writeFqdn(const std::string &fqdn, const uint32_t index=0)
Write an FQDN into a buffer.
std::string readFqdn(const uint32_t index=0) const
Read a buffer as FQDN.
void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, const uint32_t index=0)
Write prefix length and value into a buffer.
virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end)
Parses received buffer.
void writeAddress(const asiolink::IOAddress &address, const uint32_t index=0)
Write an IP address into a buffer.
virtual void pack(isc::util::OutputBuffer &buf, bool check=true) const
Writes DHCP option in a wire format to a buffer.
void initialize(const OptionBufferConstIter first, const OptionBufferConstIter last)
Sets content of this option from buffer.
const OptionBuffer & readBinary(const uint32_t index=0) const
Read a buffer as binary data.
PrefixTuple readPrefix(const uint32_t index=0) const
Read a buffer as variable length prefix.
void writePsid(const PSIDLen &psid_len, const PSID &psid, const uint32_t index=0)
Write PSID length / value into a buffer.
void writeBoolean(const bool value, const uint32_t index=0)
Write a boolean value into a buffer.
asiolink::IOAddress readAddress(const uint32_t index=0) const
Read a buffer as IP address.
PSIDTuple readPsid(const uint32_t index=0) const
Read a buffer as a PSID length / value tuple.
void writeString(const std::string &text, const uint32_t index=0)
Write a string value into a buffer.
void writeBinary(const OptionBuffer &buf, const uint32_t index=0)
Write binary data into a buffer.
void addArrayDataField(const asiolink::IOAddress &address)
Create new buffer and set its value as an IP address.
virtual OptionPtr clone() const
Copies this option and returns a pointer to the copy.
void writeTuple(const std::string &value, const uint32_t index=0)
Write a length and string tuple into a buffer.
virtual std::string toText(int indent=0) const
Returns string representation of the option.
OptionCustom(const OptionDefinition &def, Universe u)
Constructor, used for options to be sent.
uint32_t getDataFieldsNum() const
Return a number of the data fields.
static PrefixTuple readPrefix(const std::vector< uint8_t > &buf)
Read prefix from a buffer.
static asiolink::IOAddress readAddress(const std::vector< uint8_t > &buf, const short family)
Read IPv4 or IPv6 address from a buffer.
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static int getDataTypeLen(const OptionDataType data_type)
Get data type buffer length.
static std::string readFqdn(const std::vector< uint8_t > &buf)
Read FQDN from a buffer as a string value.
static std::string readTuple(const std::vector< uint8_t > &buf, OpaqueDataTuple::LengthFieldType lengthfieldtype)
Read length and string tuple from a buffer.
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
static PSIDTuple readPsid(const std::vector< uint8_t > &buf)
Read PSID length / value tuple from a buffer.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
static bool readBool(const std::vector< uint8_t > &buf)
Read boolean value from a buffer.
static std::string readString(const std::vector< uint8_t > &buf)
Read string value from a buffer.
Base class representing a DHCP option definition.
OptionDataType getType() const
Return option data type.
std::vector< OptionDataType >::const_iterator RecordFieldsConstIter
Const iterator for record data fields.
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
void validate() const
Check if the option definition is valid.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
bool getArrayType() const
Return array type indicator.
std::string headerToText(const int indent=0, const std::string &type_name="") const
Returns option header in the textual format.
Definition: option.cc:288
std::string suboptionsToText(const int indent=0) const
Returns collection of suboptions in the textual format.
Definition: option.cc:307
std::string getEncapsulatedSpace() const
Returns the name of the option space encapsulated by this option.
Definition: option.h:442
void setEncapsulatedSpace(const std::string &encapsulated_space)
Sets the name of the option space encapsulated by this option.
Definition: option.h:435
virtual const OptionBuffer & getData() const
Returns pointer to actual data.
Definition: option.h:317
virtual uint16_t getHeaderLen() const
Returns length of header (2 for v4, 4 for v6)
Definition: option.cc:321
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
void unpackOptions(const OptionBuffer &buf)
Builds a collection of sub options from the buffer.
Definition: option.cc:155
void packOptions(isc::util::OutputBuffer &buf, bool check=true) const
Store sub options in a buffer.
Definition: option.cc:136
OptionCollection options_
collection for storing suboptions
Definition: option.h:596
Universe getUniverse() const
returns option universe (V4 or V6)
Definition: option.h:233
void packHeader(isc::util::OutputBuffer &buf, bool check=true) const
Store option's header in a buffer.
Definition: option.cc:119
void check() const
A protected method used for option correctness.
Definition: option.cc:90
Encapsulates PSID length.
Encapsulates PSID value.
Encapsulates prefix length.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
std::pair< PSIDLen, PSID > PSIDTuple
Defines a pair of PSID length / value.
OptionDataType
Data types of DHCP option fields.
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:30
std::pair< PrefixLen, asiolink::IOAddress > PrefixTuple
Defines a pair of prefix length / value.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:469
Defines the logger used by the top-level component of kea-lfc.