option_custom.cc 29 KB

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