123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- // Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #include <config.h>
- #include <dhcp/libdhcp++.h>
- #include <dhcp/option_data_types.h>
- #include <dhcp/option_custom.h>
- #include <util/encode/hex.h>
- using namespace isc::asiolink;
- namespace isc {
- namespace dhcp {
- OptionCustom::OptionCustom(const OptionDefinition& def,
- Universe u)
- : Option(u, def.getCode(), OptionBuffer()),
- definition_(def) {
- setEncapsulatedSpace(def.getEncapsulatedSpace());
- createBuffers();
- }
- OptionCustom::OptionCustom(const OptionDefinition& def,
- Universe u,
- const OptionBuffer& data)
- : Option(u, def.getCode(), data.begin(), data.end()),
- definition_(def) {
- setEncapsulatedSpace(def.getEncapsulatedSpace());
- createBuffers(getData());
- }
- OptionCustom::OptionCustom(const OptionDefinition& def,
- Universe u,
- OptionBufferConstIter first,
- OptionBufferConstIter last)
- : Option(u, def.getCode(), first, last),
- definition_(def) {
- setEncapsulatedSpace(def.getEncapsulatedSpace());
- createBuffers(getData());
- }
- OptionPtr
- OptionCustom::clone() const {
- return (cloneInternal<OptionCustom>());
- }
- void
- OptionCustom::addArrayDataField(const IOAddress& address) {
- checkArrayType();
- if ((address.isV4() && definition_.getType() != OPT_IPV4_ADDRESS_TYPE) ||
- (address.isV6() && definition_.getType() != OPT_IPV6_ADDRESS_TYPE)) {
- isc_throw(BadDataTypeCast, "invalid address specified "
- << address << ". Expected a valid IPv"
- << (definition_.getType() == OPT_IPV4_ADDRESS_TYPE ?
- "4" : "6") << " address.");
- }
- OptionBuffer buf;
- OptionDataTypeUtil::writeAddress(address, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::addArrayDataField(const std::string& value) {
- checkArrayType();
- OpaqueDataTuple::LengthFieldType lft = getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES;
- OptionBuffer buf;
- OptionDataTypeUtil::writeTuple(value, lft, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::addArrayDataField(const OpaqueDataTuple& value) {
- checkArrayType();
- OptionBuffer buf;
- OptionDataTypeUtil::writeTuple(value, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::addArrayDataField(const bool value) {
- checkArrayType();
- OptionBuffer buf;
- OptionDataTypeUtil::writeBool(value, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::addArrayDataField(const PrefixLen& prefix_len,
- const asiolink::IOAddress& prefix) {
- checkArrayType();
- if (definition_.getType() != OPT_IPV6_PREFIX_TYPE) {
- isc_throw(BadDataTypeCast, "IPv6 prefix can be specified only for"
- " an option comprising an array of IPv6 prefix values");
- }
- OptionBuffer buf;
- OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::addArrayDataField(const PSIDLen& psid_len, const PSID& psid) {
- checkArrayType();
- if (definition_.getType() != OPT_PSID_TYPE) {
- isc_throw(BadDataTypeCast, "PSID value can be specified onlu for"
- " an option comprising an array of PSID length / value"
- " tuples");
- }
- OptionBuffer buf;
- OptionDataTypeUtil::writePsid(psid_len, psid, buf);
- buffers_.push_back(buf);
- }
- void
- OptionCustom::checkIndex(const uint32_t index) const {
- if (index >= buffers_.size()) {
- isc_throw(isc::OutOfRange, "specified data field index " << index
- << " is out of range.");
- }
- }
- void
- OptionCustom::createBuffers() {
- definition_.validate();
- std::vector<OptionBuffer> buffers;
- OptionDataType data_type = definition_.getType();
- // This function is called when an empty data buffer has been
- // passed to the constructor. In such cases values for particular
- // data fields will be set using modifier functions but for now
- // we need to initialize a set of buffers that are specified
- // for an option by its definition. Since there is no data yet,
- // we are going to fill these buffers with default values.
- if (data_type == OPT_RECORD_TYPE) {
- // For record types we need to iterate over all data fields
- // specified in option definition and create corresponding
- // buffers for each of them.
- const OptionDefinition::RecordFieldsCollection fields =
- definition_.getRecordFields();
- for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
- field != fields.end(); ++field) {
- OptionBuffer buf;
- // For data types that have a fixed size we can use the
- // utility function to get the buffer's size.
- size_t data_size = OptionDataTypeUtil::getDataTypeLen(*field);
- // For variable data sizes the utility function returns zero.
- // It is ok for string values because the default string
- // is 'empty'. However for FQDN the empty value is not valid
- // so we initialize it to '.'. For prefix there is a prefix
- // length fixed field.
- if (data_size == 0) {
- if (*field == OPT_FQDN_TYPE) {
- OptionDataTypeUtil::writeFqdn(".", buf);
- } else if (*field == OPT_IPV6_PREFIX_TYPE) {
- OptionDataTypeUtil::writePrefix(PrefixLen(0),
- IOAddress::IPV6_ZERO_ADDRESS(),
- buf);
- }
- } else {
- // At this point we can resize the buffer. Note that
- // for string values we are setting the empty buffer
- // here.
- buf.resize(data_size);
- }
- // We have the buffer with default value prepared so we
- // add it to the set of buffers.
- buffers.push_back(buf);
- }
- } else if (!definition_.getArrayType() &&
- data_type != OPT_EMPTY_TYPE) {
- // For either 'empty' options we don't have to create any buffers
- // for obvious reason. For arrays we also don't create any buffers
- // yet because the set of fields that belong to the array is open
- // ended so we can't allocate required buffers until we know how
- // many of them are needed.
- // For non-arrays we have a single value being held by the option
- // so we have to allocate exactly one buffer.
- OptionBuffer buf;
- size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
- if (data_size == 0) {
- if (data_type == OPT_FQDN_TYPE) {
- OptionDataTypeUtil::writeFqdn(".", buf);
- } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
- OptionDataTypeUtil::writePrefix(PrefixLen(0),
- IOAddress::IPV6_ZERO_ADDRESS(),
- buf);
- }
- } else {
- // Note that if our option holds a string value then
- // we are making empty buffer here.
- buf.resize(data_size);
- }
- // Add a buffer that we have created and leave.
- buffers.push_back(buf);
- }
- // The 'swap' is used here because we want to make sure that we
- // don't touch buffers_ until we successfully allocate all
- // buffers to be stored there.
- std::swap(buffers, buffers_);
- }
- void
- OptionCustom::createBuffers(const OptionBuffer& data_buf) {
- // Check that the option definition is correct as we are going
- // to use it to split the data_ buffer into set of sub buffers.
- definition_.validate();
- std::vector<OptionBuffer> buffers;
- OptionBuffer::const_iterator data = data_buf.begin();
- OptionDataType data_type = definition_.getType();
- if (data_type == OPT_RECORD_TYPE) {
- // An option comprises a record of data fields. We need to
- // get types of these data fields to allocate enough space
- // for each buffer.
- const OptionDefinition::RecordFieldsCollection& fields =
- definition_.getRecordFields();
- // Go over all data fields within a record.
- for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
- field != fields.end(); ++field) {
- // For fixed-size data type such as boolean, integer, even
- // IP address we can use the utility function to get the required
- // buffer size.
- size_t data_size = OptionDataTypeUtil::getDataTypeLen(*field);
- // For variable size types (e.g. string) the function above will
- // return 0 so we need to do a runtime check of the length.
- if (data_size == 0) {
- // FQDN is a special data type as it stores variable length data
- // but the data length is encoded in the buffer. The easiest way
- // to obtain the length of the data is to read the FQDN. The
- // utility function will return the size of the buffer on success.
- if (*field == OPT_FQDN_TYPE) {
- std::string fqdn =
- OptionDataTypeUtil::readFqdn(OptionBuffer(data, data_buf.end()));
- // The size of the buffer holding an FQDN is always
- // 1 byte larger than the size of the string
- // representation of this FQDN.
- data_size = fqdn.size() + 1;
- } else if ((*field == OPT_BINARY_TYPE) || (*field == OPT_STRING_TYPE)) {
- // In other case we are dealing with string or binary value
- // which size can't be determined. Thus we consume the
- // remaining part of the buffer for it. Note that variable
- // size data can be laid at the end of the option only and
- // that the validate() function in OptionDefinition object
- // should have checked wheter it is a case for this option.
- data_size = std::distance(data, data_buf.end());
- } else if (*field == OPT_IPV6_PREFIX_TYPE) {
- // The size of the IPV6 prefix type is determined as
- // one byte (which is the size of the prefix in bits)
- // followed by the prefix bits (right-padded with
- // zeros to the nearest octet boundary).
- if (std::distance(data, data_buf.end()) > 0) {
- data_size = static_cast<size_t>(sizeof(uint8_t) + (*data + 7) / 8);
- }
- } else if (*field == OPT_TUPLE_TYPE) {
- OpaqueDataTuple::LengthFieldType lft =
- getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE :
- OpaqueDataTuple::LENGTH_2_BYTES;
- std::string value =
- OptionDataTypeUtil::readTuple(OptionBuffer(data, data_buf.end()),
- lft);
- data_size = value.size();
- // The size of the buffer holding a tuple is always
- // 1 or 2 byte larger than the size of the string
- data_size += getUniverse() == Option::V4 ? 1 : 2;
- } else {
- // If we reached the end of buffer we assume that this option is
- // truncated because there is no remaining data to initialize
- // an option field.
- isc_throw(OutOfRange, "option buffer truncated");
- }
- }
- // Our data field requires that there is a certain chunk of
- // data left in the buffer. If not, option is truncated.
- if (std::distance(data, data_buf.end()) < data_size) {
- isc_throw(OutOfRange, "option buffer truncated");
- }
- // Store the created buffer.
- buffers.push_back(OptionBuffer(data, data + data_size));
- // Proceed to the next data field.
- data += data_size;
- }
- // Unpack suboptions if any.
- if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
- unpackOptions(OptionBuffer(data, data_buf.end()));
- }
- } else if (data_type != OPT_EMPTY_TYPE) {
- // If data_type value is other than OPT_RECORD_TYPE, our option is
- // empty (have no data at all) or it comprises one or more
- // data fields of the same type. The type of those fields
- // is held in the data_type variable so let's use it to determine
- // a size of buffers.
- size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
- // The check below will fail if the input buffer is too short
- // for the data size being held by this option.
- // Note that data_size returned by getDataTypeLen may be zero
- // if variable length data is being held by the option but
- // this will not cause this check to throw exception.
- if (std::distance(data, data_buf.end()) < data_size) {
- isc_throw(OutOfRange, "option buffer truncated");
- }
- // For an array of values we are taking different path because
- // we have to handle multiple buffers.
- if (definition_.getArrayType()) {
- while (data != data_buf.end()) {
- // FQDN is a special case because it is of a variable length.
- // The actual length for a particular FQDN is encoded within
- // a buffer so we have to actually read the FQDN from a buffer
- // to get it.
- if (data_type == OPT_FQDN_TYPE) {
- std::string fqdn =
- OptionDataTypeUtil::readFqdn(OptionBuffer(data, data_buf.end()));
- // The size of the buffer holding an FQDN is always
- // 1 byte larger than the size of the string
- // representation of this FQDN.
- data_size = fqdn.size() + 1;
- } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
- PrefixTuple prefix =
- OptionDataTypeUtil::readPrefix(OptionBuffer(data, data_buf.end()));
- // Data size comprises 1 byte holding a prefix length and the
- // prefix length (in bytes) rounded to the nearest byte boundary.
- data_size = sizeof(uint8_t) + (prefix.first.asUint8() + 7) / 8;
- } else if (data_type == OPT_TUPLE_TYPE) {
- OpaqueDataTuple::LengthFieldType lft =
- getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE :
- OpaqueDataTuple::LENGTH_2_BYTES;
- std::string value =
- OptionDataTypeUtil::readTuple(OptionBuffer(data, data_buf.end()),
- lft);
- data_size = value.size();
- // The size of the buffer holding a tuple is always
- // 1 or 2 byte larger than the size of the string
- data_size += getUniverse() == Option::V4 ? 1 : 2;
- }
- // We don't perform other checks for data types that can't be
- // used together with array indicator such as strings, empty field
- // etc. This is because OptionDefinition::validate function should
- // have checked this already. Thus data_size must be greater than
- // zero.
- assert(data_size > 0);
- // Get chunks of data and store as a collection of buffers.
- // Truncate any remaining part which length is not divisible by
- // data_size. Note that it is ok to truncate the data if and only
- // if the data buffer is long enough to keep at least one value.
- // This has been checked above already.
- if (std::distance(data, data_buf.end()) < data_size) {
- break;
- }
- buffers.push_back(OptionBuffer(data, data + data_size));
- data += data_size;
- }
- } else {
- // For non-arrays the data_size can be zero because
- // getDataTypeLen returns zero for variable size data types
- // such as strings. Simply take whole buffer.
- if (data_size == 0) {
- // For FQDN we get the size by actually reading the FQDN.
- if (data_type == OPT_FQDN_TYPE) {
- std::string fqdn =
- OptionDataTypeUtil::readFqdn(OptionBuffer(data, data_buf.end()));
- // The size of the buffer holding an FQDN is always
- // 1 bytes larger than the size of the string
- // representation of this FQDN.
- data_size = fqdn.size() + 1;
- } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
- if (!data_buf.empty()) {
- data_size = static_cast<size_t>
- (sizeof(uint8_t) + (data_buf[0] + 7) / 8);
- }
- } else if (data_type == OPT_TUPLE_TYPE) {
- OpaqueDataTuple::LengthFieldType lft =
- getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE :
- OpaqueDataTuple::LENGTH_2_BYTES;
- std::string value =
- OptionDataTypeUtil::readTuple(OptionBuffer(data, data_buf.end()),
- lft);
- data_size = value.size();
- // The size of the buffer holding a tuple is always
- // 1 or 2 byte larger than the size of the string
- data_size += getUniverse() == Option::V4 ? 1 : 2;
- } else {
- data_size = std::distance(data, data_buf.end());
- }
- }
- if ((data_size > 0) && (std::distance(data, data_buf.end()) >= data_size)) {
- buffers.push_back(OptionBuffer(data, data + data_size));
- data += data_size;
- } else {
- isc_throw(OutOfRange, "option buffer truncated");
- }
- // Unpack suboptions if any.
- if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
- unpackOptions(OptionBuffer(data, data_buf.end()));
- }
- }
- } else {
- // Unpack suboptions if any.
- if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
- unpackOptions(OptionBuffer(data, data_buf.end()));
- }
- }
- // If everything went ok we can replace old buffer set with new ones.
- std::swap(buffers_, buffers);
- }
- std::string
- OptionCustom::dataFieldToText(const OptionDataType data_type,
- const uint32_t index) const {
- std::ostringstream text;
- // Get the value of the data field.
- switch (data_type) {
- case OPT_BINARY_TYPE:
- text << util::encode::encodeHex(readBinary(index));
- break;
- case OPT_BOOLEAN_TYPE:
- text << (readBoolean(index) ? "true" : "false");
- break;
- case OPT_INT8_TYPE:
- text << static_cast<int>(readInteger<int8_t>(index));
- break;
- case OPT_INT16_TYPE:
- text << readInteger<int16_t>(index);
- break;
- case OPT_INT32_TYPE:
- text << readInteger<int32_t>(index);
- break;
- case OPT_UINT8_TYPE:
- text << static_cast<unsigned>(readInteger<uint8_t>(index));
- break;
- case OPT_UINT16_TYPE:
- text << readInteger<uint16_t>(index);
- break;
- case OPT_UINT32_TYPE:
- text << readInteger<uint32_t>(index);
- break;
- case OPT_IPV4_ADDRESS_TYPE:
- case OPT_IPV6_ADDRESS_TYPE:
- text << readAddress(index);
- break;
- case OPT_FQDN_TYPE:
- text << "\"" << readFqdn(index) << "\"";
- break;
- case OPT_TUPLE_TYPE:
- text << "\"" << readTuple(index) << "\"";
- break;
- case OPT_STRING_TYPE:
- text << "\"" << readString(index) << "\"";
- break;
- default:
- ;
- }
- // Append data field type in brackets.
- text << " (" << OptionDataTypeUtil::getDataTypeName(data_type) << ")";
- return (text.str());
- }
- void
- OptionCustom::pack(isc::util::OutputBuffer& buf) const {
- // Pack DHCP header (V4 or V6).
- packHeader(buf);
- // Write data from buffers.
- for (std::vector<OptionBuffer>::const_iterator it = buffers_.begin();
- it != buffers_.end(); ++it) {
- // In theory the createBuffers function should have taken
- // care that there are no empty buffers added to the
- // collection but it is almost always good to make sure.
- if (!it->empty()) {
- buf.writeData(&(*it)[0], it->size());
- }
- }
- // Write suboptions.
- packOptions(buf);
- }
- IOAddress
- OptionCustom::readAddress(const uint32_t index) const {
- checkIndex(index);
- // The address being read can be either IPv4 or IPv6. The decision
- // is made based on the buffer length. If it holds 4 bytes it is IPv4
- // address, if it holds 16 bytes it is IPv6.
- if (buffers_[index].size() == asiolink::V4ADDRESS_LEN) {
- return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET));
- } else if (buffers_[index].size() == asiolink::V6ADDRESS_LEN) {
- return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET6));
- } else {
- isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
- << " IP address. Invalid buffer length "
- << buffers_[index].size() << ".");
- }
- }
- void
- OptionCustom::writeAddress(const IOAddress& address,
- const uint32_t index) {
- checkIndex(index);
- if ((address.isV4() && buffers_[index].size() != V4ADDRESS_LEN) ||
- (address.isV6() && buffers_[index].size() != V6ADDRESS_LEN)) {
- isc_throw(BadDataTypeCast, "invalid address specified "
- << address << ". Expected a valid IPv"
- << (buffers_[index].size() == V4ADDRESS_LEN ? "4" : "6")
- << " address.");
- }
- OptionBuffer buf;
- OptionDataTypeUtil::writeAddress(address, buf);
- std::swap(buf, buffers_[index]);
- }
- const OptionBuffer&
- OptionCustom::readBinary(const uint32_t index) const {
- checkIndex(index);
- return (buffers_[index]);
- }
- void
- OptionCustom::writeBinary(const OptionBuffer& buf,
- const uint32_t index) {
- checkIndex(index);
- buffers_[index] = buf;
- }
- std::string
- OptionCustom::readTuple(const uint32_t index) const {
- checkIndex(index);
- OpaqueDataTuple::LengthFieldType lft = getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES;
- return (OptionDataTypeUtil::readTuple(buffers_[index], lft));
- }
- void
- OptionCustom::readTuple(OpaqueDataTuple& tuple,
- const uint32_t index) const {
- checkIndex(index);
- OptionDataTypeUtil::readTuple(buffers_[index], tuple);
- }
- void
- OptionCustom::writeTuple(const std::string& value, const uint32_t index) {
- checkIndex(index);
- buffers_[index].clear();
- OpaqueDataTuple::LengthFieldType lft = getUniverse() == Option::V4 ?
- OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES;
- OptionDataTypeUtil::writeTuple(value, lft, buffers_[index]);
- }
- void
- OptionCustom::writeTuple(const OpaqueDataTuple& value, const uint32_t index) {
- checkIndex(index);
- buffers_[index].clear();
- OptionDataTypeUtil::writeTuple(value, buffers_[index]);
- }
- bool
- OptionCustom::readBoolean(const uint32_t index) const {
- checkIndex(index);
- return (OptionDataTypeUtil::readBool(buffers_[index]));
- }
- void
- OptionCustom::writeBoolean(const bool value, const uint32_t index) {
- checkIndex(index);
- buffers_[index].clear();
- OptionDataTypeUtil::writeBool(value, buffers_[index]);
- }
- std::string
- OptionCustom::readFqdn(const uint32_t index) const {
- checkIndex(index);
- return (OptionDataTypeUtil::readFqdn(buffers_[index]));
- }
- void
- OptionCustom::writeFqdn(const std::string& fqdn, const uint32_t index) {
- checkIndex(index);
- // Create a temporary buffer where the FQDN will be written.
- OptionBuffer buf;
- // Try to write to the temporary buffer rather than to the
- // buffers_ member directly guarantees that we don't modify
- // (clear) buffers_ until we are sure that the provided FQDN
- // is valid.
- OptionDataTypeUtil::writeFqdn(fqdn, buf);
- // If we got to this point it means that the FQDN is valid.
- // We can move the contents of the temporary buffer to the
- // target buffer.
- std::swap(buffers_[index], buf);
- }
- PrefixTuple
- OptionCustom::readPrefix(const uint32_t index) const {
- checkIndex(index);
- return (OptionDataTypeUtil::readPrefix(buffers_[index]));
- }
- void
- OptionCustom::writePrefix(const PrefixLen& prefix_len,
- const IOAddress& prefix,
- const uint32_t index) {
- checkIndex(index);
- OptionBuffer buf;
- OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
- // If there are no errors while writing PSID to a buffer, we can
- // replace the current buffer with a new buffer.
- std::swap(buffers_[index], buf);
- }
- PSIDTuple
- OptionCustom::readPsid(const uint32_t index) const {
- checkIndex(index);
- return (OptionDataTypeUtil::readPsid(buffers_[index]));
- }
- void
- OptionCustom::writePsid(const PSIDLen& psid_len, const PSID& psid,
- const uint32_t index) {
- checkIndex(index);
- OptionBuffer buf;
- OptionDataTypeUtil::writePsid(psid_len, psid, buf);
- // If there are no errors while writing PSID to a buffer, we can
- // replace the current buffer with a new buffer.
- std::swap(buffers_[index], buf);
- }
- std::string
- OptionCustom::readString(const uint32_t index) const {
- checkIndex(index);
- return (OptionDataTypeUtil::readString(buffers_[index]));
- }
- void
- OptionCustom::writeString(const std::string& text, const uint32_t index) {
- checkIndex(index);
- // Let's clear a buffer as we want to replace the value of the
- // whole buffer. If we fail to clear the buffer the data will
- // be appended.
- buffers_[index].clear();
- // If the text value is empty we can leave because the buffer
- // is already empty.
- if (!text.empty()) {
- OptionDataTypeUtil::writeString(text, buffers_[index]);
- }
- }
- void
- OptionCustom::unpack(OptionBufferConstIter begin,
- OptionBufferConstIter end) {
- initialize(begin, end);
- }
- uint16_t
- OptionCustom::len() const {
- // The length of the option is a sum of option header ...
- size_t length = getHeaderLen();
- // ... lengths of all buffers that hold option data ...
- for (std::vector<OptionBuffer>::const_iterator buf = buffers_.begin();
- buf != buffers_.end(); ++buf) {
- length += buf->size();
- }
- // ... and lengths of all suboptions
- for (OptionCollection::const_iterator it = options_.begin();
- it != options_.end();
- ++it) {
- length += (*it).second->len();
- }
- return (static_cast<uint16_t>(length));
- }
- void OptionCustom::initialize(const OptionBufferConstIter first,
- const OptionBufferConstIter last) {
- setData(first, last);
- // Chop the data_ buffer into set of buffers that represent
- // option fields data.
- createBuffers(getData());
- }
- std::string OptionCustom::toText(int indent) const {
- std::stringstream output;
- output << headerToText(indent) << ":";
- OptionDataType data_type = definition_.getType();
- if (data_type == OPT_RECORD_TYPE) {
- const OptionDefinition::RecordFieldsCollection& fields =
- definition_.getRecordFields();
- // For record types we iterate over fields defined in
- // option definition and match the appropriate buffer
- // with them.
- for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
- field != fields.end(); ++field) {
- output << " " << dataFieldToText(*field, std::distance(fields.begin(),
- field));
- }
- } else {
- // For non-record types we iterate over all buffers
- // and print the data type set globally for an option
- // definition. We take the same code path for arrays
- // and non-arrays as they only differ in such a way that
- // non-arrays have just single data field.
- for (unsigned int i = 0; i < getDataFieldsNum(); ++i) {
- output << " " << dataFieldToText(definition_.getType(), i);
- }
- }
- // Append suboptions.
- output << suboptionsToText(indent + 2);
- return (output.str());
- }
- } // end of isc::dhcp namespace
- } // end of isc namespace
|