Kea  2.3.1-git
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>
11 #include <exceptions/isc_assert.h>
12 #include <util/encode/hex.h>
13 
14 using namespace isc::asiolink;
15 
16 namespace isc {
17 namespace dhcp {
18 
19 OptionCustom::OptionCustom(const OptionDefinition& def,
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 
51 void
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 
68 void
69 OptionCustom::addArrayDataField(const std::string& value) {
70  checkArrayType();
71 
74  OptionBuffer buf;
75  OptionDataTypeUtil::writeTuple(value, lft, buf);
76  buffers_.push_back(buf);
77 }
78 
79 void
81  checkArrayType();
82 
83  OptionBuffer buf;
85  buffers_.push_back(buf);
86 }
87 
88 void
90  checkArrayType();
91 
92  OptionBuffer buf;
94  buffers_.push_back(buf);
95 }
96 
97 void
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 
112 void
113 OptionCustom::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 
127 void
128 OptionCustom::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 
135 void
136 OptionCustom::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) {
149  OptionDataTypeUtil::writeFqdn(".", buffer);
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 
164 void
165 OptionCustom::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 
212 size_t
213 OptionCustom::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) {
259  getUniverse() == Option::V4 ?
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 
279 void
280 OptionCustom::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 
398 std::string
399 OptionCustom::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 
457 void
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 
479 IOAddress
480 OptionCustom::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 
497 void
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;
511  OptionDataTypeUtil::writeAddress(address, buf);
512  std::swap(buf, buffers_[index]);
513 }
514 
515 const OptionBuffer&
516 OptionCustom::readBinary(const uint32_t index) const {
517  checkIndex(index);
518  return (buffers_[index]);
519 }
520 
521 void
523  const uint32_t index) {
524  checkIndex(index);
525  buffers_[index] = buf;
526 }
527 
528 std::string
529 OptionCustom::readTuple(const uint32_t index) const {
530  checkIndex(index);
533  return (OptionDataTypeUtil::readTuple(buffers_[index], lft));
534 }
535 
536 void
538  const uint32_t index) const {
539  checkIndex(index);
540  OptionDataTypeUtil::readTuple(buffers_[index], tuple);
541 }
542 
543 void
544 OptionCustom::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 
553 void
554 OptionCustom::writeTuple(const OpaqueDataTuple& value, const uint32_t index) {
555  checkIndex(index);
556 
557  buffers_[index].clear();
558  OptionDataTypeUtil::writeTuple(value, buffers_[index]);
559 }
560 
561 bool
562 OptionCustom::readBoolean(const uint32_t index) const {
563  checkIndex(index);
564  return (OptionDataTypeUtil::readBool(buffers_[index]));
565 }
566 
567 void
568 OptionCustom::writeBoolean(const bool value, const uint32_t index) {
569  checkIndex(index);
570 
571  buffers_[index].clear();
572  OptionDataTypeUtil::writeBool(value, buffers_[index]);
573 }
574 
575 std::string
576 OptionCustom::readFqdn(const uint32_t index) const {
577  checkIndex(index);
578  return (OptionDataTypeUtil::readFqdn(buffers_[index]));
579 }
580 
581 void
582 OptionCustom::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 
599 OptionCustom::readPrefix(const uint32_t index) const {
600  checkIndex(index);
601  return (OptionDataTypeUtil::readPrefix(buffers_[index]));
602 }
603 
604 void
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 
618 PSIDTuple
619 OptionCustom::readPsid(const uint32_t index) const {
620  checkIndex(index);
621  return (OptionDataTypeUtil::readPsid(buffers_[index]));
622 }
623 
624 void
625 OptionCustom::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 
637 std::string
638 OptionCustom::readString(const uint32_t index) const {
639  checkIndex(index);
640  return (OptionDataTypeUtil::readString(buffers_[index]));
641 }
642 
643 void
644 OptionCustom::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 
658 void
660  OptionBufferConstIter end) {
661  initialize(begin, end);
662 }
663 
664 uint16_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 
694 std::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
void writeTuple(const std::string &value, const uint32_t index=0)
Write a length and string tuple into a buffer.
std::string suboptionsToText(const int indent=0) const
Returns collection of suboptions in the textual format.
Definition: option.cc:307
void addArrayDataField(const asiolink::IOAddress &address)
Create new buffer and set its value as an IP address.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
Encapsulates PSID length.
asiolink::IOAddress readAddress(const uint32_t index=0) const
Read a buffer as IP address.
Base class representing a DHCP option definition.
uint32_t getDataFieldsNum() const
Return a number of the data fields.
void writeAddress(const asiolink::IOAddress &address, const uint32_t index=0)
Write an IP address into a buffer.
bool readBoolean(const uint32_t index=0) const
Read a buffer as boolean value.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static std::string readFqdn(const std::vector< uint8_t > &buf)
Read FQDN from a buffer as a string value.
std::string readFqdn(const uint32_t index=0) const
Read a buffer as FQDN.
virtual void pack(isc::util::OutputBuffer &buf, bool check=true) const
Writes DHCP option in a wire format to a buffer.
OptionCustom(const OptionDefinition &def, Universe u)
Constructor, used for options to be sent.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
static int getDataTypeLen(const OptionDataType data_type)
Get data type buffer length.
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
void packHeader(isc::util::OutputBuffer &buf, bool check=true) const
Store option&#39;s header in a buffer.
Definition: option.cc:119
static bool readBool(const std::vector< uint8_t > &buf)
Read boolean value from a buffer.
std::pair< PrefixLen, asiolink::IOAddress > PrefixTuple
Defines a pair of prefix length / value.
virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end)
Parses received buffer.
void writeBoolean(const bool value, const uint32_t index=0)
Write a boolean value into a buffer.
virtual uint16_t getHeaderLen() const
Returns length of header (2 for v4, 4 for v6)
Definition: option.cc:321
PSIDTuple readPsid(const uint32_t index=0) const
Read a buffer as a PSID length / value tuple.
static PSIDTuple readPsid(const std::vector< uint8_t > &buf)
Read PSID length / value tuple from a buffer.
virtual uint16_t len() const
Returns length of the complete option (data length + DHCPv4/DHCPv6 option header) ...
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
std::string readTuple(const uint32_t index=0) const
Read a buffer as length and string tuple.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void packOptions(isc::util::OutputBuffer &buf, bool check=true) const
Store sub options in a buffer.
Definition: option.cc:136
static std::string readString(const std::vector< uint8_t > &buf)
Read string value from a buffer.
std::string headerToText(const int indent=0, const std::string &type_name="") const
Returns option header in the textual format.
Definition: option.cc:288
OptionDataType
Data types of DHCP option fields.
Universe getUniverse() const
returns option universe (V4 or V6)
Definition: option.h:233
Encapsulates PSID value.
virtual OptionPtr clone() const
Copies this option and returns a pointer to the copy.
OptionCollection options_
collection for storing suboptions
Definition: option.h:596
void writePsid(const PSIDLen &psid_len, const PSID &psid, const uint32_t index=0)
Write PSID length / value into a buffer.
virtual const OptionBuffer & getData() const
Returns pointer to actual data.
Definition: option.h:317
void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, const uint32_t index=0)
Write prefix length and value into a buffer.
void check() const
A protected method used for option correctness.
Definition: option.cc:90
void setEncapsulatedSpace(const std::string &encapsulated_space)
Sets the name of the option space encapsulated by this option.
Definition: option.h:435
PrefixTuple readPrefix(const uint32_t index=0) const
Read a buffer as variable length prefix.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:30
LengthFieldType
Size of the length field in the tuple.
static asiolink::IOAddress readAddress(const std::vector< uint8_t > &buf, const short family)
Read IPv4 or IPv6 address from a buffer.
std::pair< PSIDLen, PSID > PSIDTuple
Defines a pair of PSID length / value.
Defines the logger used by the top-level component of kea-lfc.
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 (&#39;hex&#39;) format.
Definition: base_n.cc:469
void unpackOptions(const OptionBuffer &buf)
Builds a collection of sub options from the buffer.
Definition: option.cc:155
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
void writeBinary(const OptionBuffer &buf, const uint32_t index=0)
Write binary data into a buffer.
static std::string readTuple(const std::vector< uint8_t > &buf, OpaqueDataTuple::LengthFieldType lengthfieldtype)
Read length and string tuple from a buffer.
virtual std::string toText(int indent=0) const
Returns string representation of the option.
std::string getEncapsulatedSpace() const
Returns the name of the option space encapsulated by this option.
Definition: option.h:442
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
void validate() const
Check if the option definition is valid.
void writeFqdn(const std::string &fqdn, const uint32_t index=0)
Write an FQDN into a buffer.
static PrefixTuple readPrefix(const std::vector< uint8_t > &buf)
Read prefix from a buffer.
Represents a single instance of the opaque data preceded by length.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
std::vector< OptionDataType >::const_iterator RecordFieldsConstIter
Const iterator for record data fields.
Exception to be thrown when cast to the data type was unsuccessful.
std::string readString(const uint32_t index=0) const
Read a buffer as string value.
bool getArrayType() const
Return array type indicator.
OptionDataType getType() const
Return option data type.
void setData(InputIterator first, InputIterator last)
Sets content of this option from buffer.
Definition: option.h:427
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
Encapsulates prefix length.
void writeString(const std::string &text, const uint32_t index=0)
Write a string value into 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.