Bug Summary

File:home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmp_xzd2v8m/../../../src/lib/dhcp/option_data_types.cc
Warning:line 528, column 40
The result of right shift is undefined because the right operand is negative

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name option_data_types.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmp_xzd2v8m -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmp_xzd2v8m -resource-dir /usr/bin/../lib/clang/22 -I src/lib/dhcp/libkea-dhcp.so.129.0.0.p -I src/lib/dhcp -I ../../../src/lib/dhcp -I . -I ../../.. -I src -I ../../../src -I src/bin -I ../../../src/bin -I src/lib -I ../../../src/lib -I /usr/include -D _GLIBCXX_ASSERTIONS=1 -D _FILE_OFFSET_BITS=64 -D BOOST_ALL_NO_LIB -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/backward -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-missing-field-initializers -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-logs/scanbuild/2026-08-13-132751-4729-1 -x c++ ../../../src/lib/dhcp/option_data_types.cc
1// Copyright (C) 2012-2026 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
9#include <dhcp/option_data_types.h>
10#include <dns/labelsequence.h>
11#include <dns/name.h>
12#include <util/io.h>
13#include <util/str.h>
14#include <util/encode/encode.h>
15#include <algorithm>
16#include <limits>
17
18using namespace isc::asiolink;
19
20namespace {
21/// @brief Bit mask used to compute PSID value.
22///
23/// The mask represents the useful bits of the PSID. The value 0 is a special
24/// case because the RFC explicitly specifies that PSID value should be ignored
25/// if psid_len is 0.
26std::vector<uint16_t> psid_bitmask = { 0xffff,
27 0x8000, 0xc000, 0xe000, 0xf000,
28 0xf800, 0xfc00, 0xfe00, 0xff00,
29 0xff80, 0xffc0, 0xffe0, 0xfff0,
30 0xfff8, 0xfffc, 0xfffe, 0xffff
31};
32}
33
34namespace isc {
35namespace dhcp {
36
37OptionDataTypeUtil::OptionDataTypeUtil() {
38 data_types_["empty"] = OPT_EMPTY_TYPE;
39 data_types_["binary"] = OPT_BINARY_TYPE;
40 data_types_["boolean"] = OPT_BOOLEAN_TYPE;
41 data_types_["int8"] = OPT_INT8_TYPE;
42 data_types_["int16"] = OPT_INT16_TYPE;
43 data_types_["int32"] = OPT_INT32_TYPE;
44 data_types_["uint8"] = OPT_UINT8_TYPE;
45 data_types_["uint16"] = OPT_UINT16_TYPE;
46 data_types_["uint32"] = OPT_UINT32_TYPE;
47 data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
48 data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
49 data_types_["ipv6-prefix"] = OPT_IPV6_PREFIX_TYPE;
50 data_types_["psid"] = OPT_PSID_TYPE;
51 data_types_["string"] = OPT_STRING_TYPE;
52 data_types_["tuple"] = OPT_TUPLE_TYPE;
53 data_types_["fqdn"] = OPT_FQDN_TYPE;
54 data_types_["internal"] = OPT_INTERNAL_TYPE;
55 data_types_["record"] = OPT_RECORD_TYPE;
56
57 data_type_names_[OPT_EMPTY_TYPE] = "empty";
58 data_type_names_[OPT_BINARY_TYPE] = "binary";
59 data_type_names_[OPT_BOOLEAN_TYPE] = "boolean";
60 data_type_names_[OPT_INT8_TYPE] = "int8";
61 data_type_names_[OPT_INT16_TYPE] = "int16";
62 data_type_names_[OPT_INT32_TYPE] = "int32";
63 data_type_names_[OPT_UINT8_TYPE] = "uint8";
64 data_type_names_[OPT_UINT16_TYPE] = "uint16";
65 data_type_names_[OPT_UINT32_TYPE] = "uint32";
66 data_type_names_[OPT_IPV4_ADDRESS_TYPE] = "ipv4-address";
67 data_type_names_[OPT_IPV6_ADDRESS_TYPE] = "ipv6-address";
68 data_type_names_[OPT_IPV6_PREFIX_TYPE] = "ipv6-prefix";
69 data_type_names_[OPT_PSID_TYPE] = "psid";
70 data_type_names_[OPT_STRING_TYPE] = "string";
71 data_type_names_[OPT_TUPLE_TYPE] = "tuple";
72 data_type_names_[OPT_FQDN_TYPE] = "fqdn";
73 data_type_names_[OPT_INTERNAL_TYPE] = "internal";
74 data_type_names_[OPT_RECORD_TYPE] = "record";
75 // The "unknown" data type is declared here so as
76 // it can be returned by reference by a getDataTypeName
77 // function it no other type is suitable. Other than that
78 // this is unused.
79 data_type_names_[OPT_UNKNOWN_TYPE] = "unknown";
80}
81
82OptionDataType
83OptionDataTypeUtil::getDataType(const std::string& data_type) {
84 return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type));
85}
86
87OptionDataType
88OptionDataTypeUtil::getDataTypeImpl(const std::string& data_type) const {
89 std::map<std::string, OptionDataType>::const_iterator data_type_it =
90 data_types_.find(data_type);
91 if (data_type_it != data_types_.end()) {
92 return (data_type_it->second);
93 }
94 return (OPT_UNKNOWN_TYPE);
95}
96
97int
98OptionDataTypeUtil::getDataTypeLen(const OptionDataType data_type) {
99 switch (data_type) {
100 case OPT_BOOLEAN_TYPE:
101 case OPT_INT8_TYPE:
102 case OPT_UINT8_TYPE:
103 return (1);
104
105 case OPT_INT16_TYPE:
106 case OPT_UINT16_TYPE:
107 return (2);
108
109 case OPT_INT32_TYPE:
110 case OPT_UINT32_TYPE:
111 return (4);
112
113 case OPT_IPV4_ADDRESS_TYPE:
114 return (asiolink::V4ADDRESS_LEN);
115
116 case OPT_IPV6_ADDRESS_TYPE:
117 return (asiolink::V6ADDRESS_LEN);
118
119 case OPT_PSID_TYPE:
120 return (3);
121
122 default:
123 ;
124 }
125 return (0);
126}
127
128const std::string&
129OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) {
130 return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type));
131}
132
133const std::string&
134OptionDataTypeUtil::getDataTypeNameImpl(const OptionDataType data_type) const {
135 std::map<OptionDataType, std::string>::const_iterator data_type_it =
136 data_type_names_.find(data_type);
137 if (data_type_it != data_type_names_.end()) {
138 return (data_type_it->second);
139 }
140 return (data_type_names_.find(OPT_UNKNOWN_TYPE)->second);
141}
142
143OptionDataTypeUtil&
144OptionDataTypeUtil::instance() {
145 static OptionDataTypeUtil instance;
146 return (instance);
147}
148
149asiolink::IOAddress
150OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf,
151 const short family) {
152 using namespace isc::asiolink;
153 if (family == AF_INET2) {
154 if (buf.size() < V4ADDRESS_LEN) {
155 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IPv4 address. Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 156, oss__.str().c_str()); } while (1)
156 << " IPv4 address. Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IPv4 address. Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 156, oss__.str().c_str()); } while (1)
;
157 }
158 return (IOAddress::fromBytes(AF_INET2, &buf[0]));
159 } else if (family == AF_INET610) {
160 if (buf.size() < V6ADDRESS_LEN) {
161 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IPv6 address. Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 162, oss__.str().c_str()); } while (1)
162 << " IPv6 address. Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IPv6 address. Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 162, oss__.str().c_str()); } while (1)
;
163 }
164 return (IOAddress::fromBytes(AF_INET610, &buf[0]));
165 } else {
166 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IP address. Invalid family: " << family; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 167, oss__.str().c_str()); } while (1)
167 << " IP address. Invalid family: " << family)do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " IP address. Invalid family: " << family; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 167, oss__.str().c_str()); } while (1)
;
168 }
169}
170
171void
172OptionDataTypeUtil::writeAddress(const asiolink::IOAddress& address,
173 std::vector<uint8_t>& buf) {
174 const std::vector<uint8_t>& vec = address.toBytes();
175 buf.insert(buf.end(), vec.begin(), vec.end());
176}
177
178void
179OptionDataTypeUtil::writeBinary(const std::string& hex_str,
180 std::vector<uint8_t>& buf) {
181 // Binary value means that the value is encoded as a string
182 // of hexadecimal digits. We need to decode this string
183 // to the binary format here.
184 OptionBuffer binary;
185 try {
186 util::encode::decodeHex(hex_str, binary);
187 } catch (const Exception& ex) {
188 isc_throw(BadDataTypeCast, "unable to cast " << hex_strdo { std::ostringstream oss__; oss__ << "unable to cast "
<< hex_str << " to binary data type: " << ex
.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 189, oss__.str().c_str()); } while (1)
189 << " to binary data type: " << ex.what())do { std::ostringstream oss__; oss__ << "unable to cast "
<< hex_str << " to binary data type: " << ex
.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 189, oss__.str().c_str()); } while (1)
;
190 }
191 // Decode was successful so append decoded binary value
192 // to the buffer.
193 buf.insert(buf.end(), binary.begin(), binary.end());
194}
195
196OpaqueDataTuple::LengthFieldType
197OptionDataTypeUtil::getTupleLenFieldType(Option::Universe u) {
198 if (u == Option::V4) {
199 return (OpaqueDataTuple::LENGTH_1_BYTE);
200 }
201 return (OpaqueDataTuple::LENGTH_2_BYTES);
202}
203
204std::string
205OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
206 OpaqueDataTuple::LengthFieldType lengthfieldtype) {
207 if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
208 if (buf.size() < 1) {
209 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 211, oss__.str().c_str()); } while (1)
210 << " tuple (length). Invalid buffer size: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 211, oss__.str().c_str()); } while (1)
211 << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 211, oss__.str().c_str()); } while (1)
;
212 }
213 uint8_t len = buf[0];
214 if (buf.size() < 1 + static_cast<size_t>(len)) {
215 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << static_cast<unsigned>
(len) << "). Invalid buffer size: " << buf.size()
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 217, oss__.str().c_str()); } while (1)
216 << " tuple (length " << static_cast<unsigned>(len)do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << static_cast<unsigned>
(len) << "). Invalid buffer size: " << buf.size()
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 217, oss__.str().c_str()); } while (1)
217 << "). Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << static_cast<unsigned>
(len) << "). Invalid buffer size: " << buf.size()
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 217, oss__.str().c_str()); } while (1)
;
218 }
219 std::string value;
220 value.resize(len);
221 std::memcpy(&value[0], &buf[1], len);
222 return (value);
223 } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
224 if (buf.size() < 2) {
225 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 227, oss__.str().c_str()); } while (1)
226 << " tuple (length). Invalid buffer size: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 227, oss__.str().c_str()); } while (1)
227 << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length). Invalid buffer size: " << buf
.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 227, oss__.str().c_str()); } while (1)
;
228 }
229 uint16_t len = isc::util::readUint16(&buf[0], 2);
230 if (buf.size() < 2 + static_cast<size_t>(len)) {
231 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << len << "). Invalid buffer size: "
<< buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 233, oss__.str().c_str()); } while (1)
232 << " tuple (length " << lendo { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << len << "). Invalid buffer size: "
<< buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 233, oss__.str().c_str()); } while (1)
233 << "). Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple (length " << len << "). Invalid buffer size: "
<< buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 233, oss__.str().c_str()); } while (1)
;
234 }
235 std::string value;
236 value.resize(len);
237 std::memcpy(&value[0], &buf[2], len);
238 return (value);
239 } else {
240 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 242, oss__.str().c_str()); } while (1)
241 << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 242, oss__.str().c_str()); } while (1)
242 << static_cast<unsigned>(lengthfieldtype))do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 242, oss__.str().c_str()); } while (1)
;
243 }
244}
245
246void
247OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
248 OpaqueDataTuple& tuple) {
249 try {
250 tuple.unpack(buf.begin(), buf.end());
251 } catch (const OpaqueDataTupleError& ex) {
252 isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 252, oss__.str().c_str()); } while (1)
;
253 }
254}
255
256void
257OptionDataTypeUtil::writeTuple(const std::string& value,
258 OpaqueDataTuple::LengthFieldType lengthfieldtype,
259 std::vector<uint8_t>& buf) {
260 if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
261 if (value.size() > std::numeric_limits<uint8_t>::max()) {
262 isc_throw(BadDataTypeCast, "invalid tuple value (size "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << +std
::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str
().c_str()); } while (1)
263 << value.size() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << +std
::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str
().c_str()); } while (1)
264 << +std::numeric_limits<uint8_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << +std
::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str
().c_str()); } while (1)
;
265 }
266 buf.push_back(static_cast<uint8_t>(value.size()));
267
268 } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
269 if (value.size() > std::numeric_limits<uint16_t>::max()) {
270 isc_throw(BadDataTypeCast, "invalid tuple value (size "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << std::
numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str
().c_str()); } while (1)
271 << value.size() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << std::
numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str
().c_str()); } while (1)
272 << std::numeric_limits<uint16_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< value.size() << " larger than " << std::
numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str
().c_str()); } while (1)
;
273 }
274 buf.resize(buf.size() + 2);
275 isc::util::writeUint16(static_cast<uint16_t>(value.size()),
276 &buf[buf.size() - 2], 2);
277 } else {
278 isc_throw(BadDataTypeCast, "unable to write data to the buffer as"do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 280, oss__.str().c_str()); } while (1)
279 << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 280, oss__.str().c_str()); } while (1)
280 << static_cast<unsigned>(lengthfieldtype))do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << static_cast
<unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 280, oss__.str().c_str()); } while (1)
;
281 }
282 buf.insert(buf.end(), value.begin(), value.end());
283}
284
285void
286OptionDataTypeUtil::writeTuple(const OpaqueDataTuple& tuple,
287 std::vector<uint8_t>& buf) {
288 if (tuple.getLength() == 0) {
289 isc_throw(BadDataTypeCast, "invalid empty tuple value")do { std::ostringstream oss__; oss__ << "invalid empty tuple value"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 289, oss__.str().c_str()); } while (1)
;
290 }
291 if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_1_BYTE) {
292 if (tuple.getLength() > std::numeric_limits<uint8_t>::max()) {
293 isc_throw(BadDataTypeCast, "invalid tuple value (size "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
+std::numeric_limits<uint8_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 295, oss__.str().c_str()); } while (1)
294 << tuple.getLength() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
+std::numeric_limits<uint8_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 295, oss__.str().c_str()); } while (1)
295 << +std::numeric_limits<uint8_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
+std::numeric_limits<uint8_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 295, oss__.str().c_str()); } while (1)
;
296 }
297 buf.push_back(static_cast<uint8_t>(tuple.getLength()));
298
299 } else if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_2_BYTES) {
300 if (tuple.getLength() > std::numeric_limits<uint16_t>::max()) {
301 isc_throw(BadDataTypeCast, "invalid tuple value (size "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
std::numeric_limits<uint16_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 303, oss__.str().c_str()); } while (1)
302 << tuple.getLength() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
std::numeric_limits<uint16_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 303, oss__.str().c_str()); } while (1)
303 << std::numeric_limits<uint16_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size "
<< tuple.getLength() << " larger than " <<
std::numeric_limits<uint16_t>::max() << ")"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 303, oss__.str().c_str()); } while (1)
;
304 }
305 buf.resize(buf.size() + 2);
306 isc::util::writeUint16(static_cast<uint16_t>(tuple.getLength()),
307 &buf[buf.size() - 2], 2);
308 } else {
309 isc_throw(BadDataTypeCast, "unable to write data to the buffer as"do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << tuple
.getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 311, oss__.str().c_str()); } while (1)
310 << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << tuple
.getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 311, oss__.str().c_str()); } while (1)
311 << tuple.getLengthFieldType())do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as"
<< " tuple. Invalid length type field: " << tuple
.getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 311, oss__.str().c_str()); } while (1)
;
312 }
313 buf.insert(buf.end(), tuple.getData().begin(), tuple.getData().end());
314}
315
316bool
317OptionDataTypeUtil::readBool(const std::vector<uint8_t>& buf) {
318 if (buf.empty()) {
319 isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean"
<< " value. Invalid buffer size " << buf.size();
throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 320, oss__.str().c_str()); } while (1)
320 << " value. Invalid buffer size " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean"
<< " value. Invalid buffer size " << buf.size();
throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 320, oss__.str().c_str()); } while (1)
;
321 }
322 if (buf[0] == 1) {
323 return (true);
324 } else if (buf[0] == 0) {
325 return (false);
326 }
327 isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean"
<< " value. Invalid value " << static_cast<int
>(buf[0]); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 328, oss__.str().c_str()); } while (1)
328 << " value. Invalid value " << static_cast<int>(buf[0]))do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean"
<< " value. Invalid value " << static_cast<int
>(buf[0]); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 328, oss__.str().c_str()); } while (1)
;
329}
330
331void
332OptionDataTypeUtil::writeBool(const bool value,
333 std::vector<uint8_t>& buf) {
334 buf.push_back(static_cast<uint8_t>(value ? 1 : 0));
335}
336
337std::string
338OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf,
339 bool raw /* = false */) {
340 // If buffer is empty emit an error.
341 if (buf.empty()) {
342 isc_throw(BadDataTypeCast, "unable to read FQDN from a buffer."do { std::ostringstream oss__; oss__ << "unable to read FQDN from a buffer."
<< " The buffer is empty."; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 343, oss__.str().c_str()); } while (1)
343 << " The buffer is empty.")do { std::ostringstream oss__; oss__ << "unable to read FQDN from a buffer."
<< " The buffer is empty."; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 343, oss__.str().c_str()); } while (1)
;
344 }
345 // Set up an InputBuffer so as we can use isc::dns::Name object to get the FQDN.
346 isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size());
347 try {
348 // Try to create an object from the buffer. If exception is thrown
349 // it means that the buffer doesn't hold a valid domain name (invalid
350 // syntax).
351 isc::dns::Name name(in_buf);
352 if (!raw) {
353 return (name.toText());
354 } else {
355 return (name.toRawText());
356 }
357 } catch (const isc::Exception& ex) {
358 // Unable to convert the data in the buffer into FQDN.
359 isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 359, oss__.str().c_str()); } while (1)
;
360 }
361}
362
363void
364OptionDataTypeUtil::writeFqdn(const std::string& fqdn,
365 std::vector<uint8_t>& buf,
366 bool downcase) {
367 try {
368 isc::dns::Name name(fqdn, downcase);
369 isc::dns::LabelSequence labels(name);
370 if (labels.getDataLength() > 0) {
371 size_t read_len = 0;
372 const uint8_t* data = labels.getData(&read_len);
373 buf.insert(buf.end(), data, data + read_len);
374 }
375 } catch (const isc::Exception& ex) {
376 isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 376, oss__.str().c_str()); } while (1)
;
377 }
378}
379
380unsigned int
381OptionDataTypeUtil::getLabelCount(const std::string& text_name) {
382 // The isc::dns::Name class doesn't accept empty names. However, in some
383 // cases we may be dealing with empty names (e.g. sent by the DHCP clients).
384 // Empty names should not be sent as hostnames but if they are, for some
385 // reason, we don't want to throw an exception from this function. We
386 // rather want to signal empty name by returning 0 number of labels.
387 if (text_name.empty()) {
388 return (0);
389 }
390 try {
391 isc::dns::Name name(text_name);
392 return (name.getLabelCount());
393 } catch (const isc::Exception& ex) {
394 isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 394, oss__.str().c_str()); } while (1)
;
395 }
396}
397
398PrefixTuple
399OptionDataTypeUtil::readPrefix(const std::vector<uint8_t>& buf) {
400 // Prefix typically consists of the prefix length and the
401 // actual value. If prefix length is 0, the buffer length should
402 // be at least 1 byte to hold this length value.
403 if (buf.empty()) {
404 isc_throw(BadDataTypeCast, "unable to read prefix length from "do { std::ostringstream oss__; oss__ << "unable to read prefix length from "
"a truncated buffer"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 405, oss__.str().c_str()); } while (1)
405 "a truncated buffer")do { std::ostringstream oss__; oss__ << "unable to read prefix length from "
"a truncated buffer"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 405, oss__.str().c_str()); } while (1)
;
406 }
407
408 // Surround everything with try-catch to unify exceptions being
409 // thrown by various functions and constructors.
410 try {
411 // Try to create PrefixLen object from the prefix length held
412 // in the buffer. This may cause an exception if the length is
413 // invalid (greater than 128).
414 PrefixLen prefix_len(buf.at(0));
415
416 // Convert prefix length to bytes, because we operate on bytes,
417 // rather than bits.
418 uint8_t prefix_len_bytes = (prefix_len.asUint8() / 8);
419 // Check if we need to zero pad any bits. This is the case when
420 // the prefix length is not divisible by 8 (bits per byte). The
421 // calculations below may require some explanations. We first
422 // perform prefix_len % 8 to get the number of useful bits beyond
423 // the current prefix_len_bytes value. By substracting it from 8
424 // we get the number of zero padded bits, but with the special
425 // case of 8 when the result of substraction is 0. The value of
426 // 8 really means no padding so we make a modulo division once
427 // again to turn 8s to 0s.
428 const uint8_t zero_padded_bits =
429 static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
430 // If there are zero padded bits, it means that we need an extra
431 // byte to be retrieved from the buffer.
432 if (zero_padded_bits > 0) {
433 ++prefix_len_bytes;
434 }
435
436 // Make sure that the buffer is long enough. We substract 1 to
437 // also account for the fact that the buffer includes a prefix
438 // length besides a prefix.
439 if ((buf.size() - 1) < prefix_len_bytes) {
440 isc_throw(BadDataTypeCast, "unable to read a prefix having length of "do { std::ostringstream oss__; oss__ << "unable to read a prefix having length of "
<< prefix_len.asUnsigned() << " from a truncated buffer"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 441, oss__.str().c_str()); } while (1)
441 << prefix_len.asUnsigned() << " from a truncated buffer")do { std::ostringstream oss__; oss__ << "unable to read a prefix having length of "
<< prefix_len.asUnsigned() << " from a truncated buffer"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 441, oss__.str().c_str()); } while (1)
;
442 }
443
444 // It is possible for a prefix to be zero if the prefix length
445 // is zero.
446 IOAddress prefix(IOAddress::IPV6_ZERO_ADDRESS());
447
448 // If there is anything more than prefix length is this buffer
449 // we need to read it.
450 if (buf.size() > 1) {
451 // Buffer has to be copied, because we will modify its
452 // contents by setting certain bits to 0, if necessary.
453 std::vector<uint8_t> prefix_buf(buf.begin() + 1, buf.end());
454 // All further conversions require that the buffer length is
455 // 16 bytes.
456 if (prefix_buf.size() < V6ADDRESS_LEN) {
457 prefix_buf.resize(V6ADDRESS_LEN);
458 if (prefix_len_bytes < prefix_buf.size()) {
459 // Zero all bits in the buffer beyond prefix length
460 // position.
461 std::fill(prefix_buf.begin() + prefix_len_bytes,
462 prefix_buf.end(), 0);
463
464 if (zero_padded_bits) {
465 // There is a byte that require zero padding. We
466 // achieve that by shifting the value of that byte
467 // back and forth by the number of zeroed bits.
468 prefix_buf.at(prefix_len_bytes - 1) =
469 (prefix_buf.at(prefix_len_bytes - 1)
470 >> zero_padded_bits)
471 << zero_padded_bits;
472 }
473 }
474 }
475 // Convert the buffer to the IOAddress object.
476 prefix = IOAddress::fromBytes(AF_INET610, &prefix_buf[0]);
477 }
478
479 return (std::make_pair(prefix_len, prefix));
480
481 } catch (const BadDataTypeCast& ex) {
482 // Pass through the BadDataTypeCast exceptions.
483 throw;
484
485 } catch (const std::exception& ex) {
486 // If an exception of a different type has been thrown, insert
487 // a text that indicates that the failure occurred during reading
488 // the prefix and modify exception type to BadDataTypeCast.
489 isc_throw(BadDataTypeCast, "unable to read a prefix from a buffer: "do { std::ostringstream oss__; oss__ << "unable to read a prefix from a buffer: "
<< ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 490, oss__.str().c_str()); } while (1)
490 << ex.what())do { std::ostringstream oss__; oss__ << "unable to read a prefix from a buffer: "
<< ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 490, oss__.str().c_str()); } while (1)
;
491 }
492}
493
494void
495OptionDataTypeUtil::writePrefix(const PrefixLen& prefix_len,
496 const IOAddress& prefix,
497 std::vector<uint8_t>& buf) {
498 // Prefix must be an IPv6 prefix.
499 if (!prefix.isV6()) {
1
Taking false branch
500 isc_throw(BadDataTypeCast, "illegal prefix value "do { std::ostringstream oss__; oss__ << "illegal prefix value "
<< prefix; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 501, oss__.str().c_str()); } while (1)
501 << prefix)do { std::ostringstream oss__; oss__ << "illegal prefix value "
<< prefix; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 501, oss__.str().c_str()); } while (1)
;
502 }
503
504 // We don't need to validate the prefix_len value, because it is
505 // already validated by the PrefixLen class.
506 buf.push_back(prefix_len.asUint8());
507
508 // Convert the prefix length to a number of bytes.
509 uint8_t prefix_len_bytes = prefix_len.asUint8() / 8;
510 // Check if there are any bits that require zero padding. See the
511 // commentary in readPrefix to see how this is calculated.
512 const uint8_t zero_padded_bits =
2
'zero_padded_bits' initialized here
513 static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
514 // If zero padding is needed it means that we need to extend the
515 // buffer to hold the "partially occupied" byte.
516 if (zero_padded_bits > 0) {
3
Assuming 'zero_padded_bits' is <= 0
4
Taking false branch
517 ++prefix_len_bytes;
518 }
519
520 // Convert the prefix to byte representation and append it to
521 // our output buffer.
522 std::vector<uint8_t> prefix_bytes = prefix.toBytes();
523 buf.insert(buf.end(), prefix_bytes.begin(),
524 prefix_bytes.begin() + prefix_len_bytes);
525 // If the last byte requires zero padding we achieve that by shifting
526 // bits back and forth by the number of insignificant bits.
527 if (zero_padded_bits) {
5
Assuming 'zero_padded_bits' is not equal to 0
6
Taking true branch
528 *buf.rbegin() = (*buf.rbegin() >> zero_padded_bits) << zero_padded_bits;
7
The result of right shift is undefined because the right operand is negative
529 }
530}
531
532PSIDTuple
533OptionDataTypeUtil::readPsid(const std::vector<uint8_t>& buf) {
534 if (buf.size() < 3) {
535 isc_throw(BadDataTypeCast, "unable to read PSID from the buffer."do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer."
<< " Invalid buffer size " << buf.size() <<
". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 537, oss__.str
().c_str()); } while (1)
536 << " Invalid buffer size " << buf.size()do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer."
<< " Invalid buffer size " << buf.size() <<
". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 537, oss__.str
().c_str()); } while (1)
537 << ". Expected 3 bytes (PSID length and PSID value)")do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer."
<< " Invalid buffer size " << buf.size() <<
". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 537, oss__.str
().c_str()); } while (1)
;
538 }
539
540 // Read PSID length.
541 uint8_t psid_len = buf[0];
542
543 // PSID length must not be greater than 16 bits.
544 if (psid_len > (sizeof(uint16_t) * 8)) {
545 isc_throw(BadDataTypeCast, "invalid PSID length value "do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 547, oss__.str().c_str()); } while (1)
546 << static_cast<unsigned>(psid_len)do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 547, oss__.str().c_str()); } while (1)
547 << ", this value is expected to be in range of 0 to 16")do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 547, oss__.str().c_str()); } while (1)
;
548 }
549
550 // Read two bytes of PSID value.
551 uint16_t psid = isc::util::readUint16(&buf[1], 2);
552
553 // We need to check that the PSID value does not exceed the maximum value
554 // for a specified PSID length. That means that all bits placed further than
555 // psid_len from the left must be set to 0.
556 // The value 0 is a special case because the RFC explicitly says that the
557 // PSID value should be ignored if psid_len is 0.
558 if ((psid & ~psid_bitmask[psid_len]) != 0) {
559 isc_throw(BadDataTypeCast, "invalid PSID value " << psiddo { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid << " for a specified PSID length " <<
static_cast<unsigned>(psid_len); throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 561, oss__.str
().c_str()); } while (1)
560 << " for a specified PSID length "do { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid << " for a specified PSID length " <<
static_cast<unsigned>(psid_len); throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 561, oss__.str
().c_str()); } while (1)
561 << static_cast<unsigned>(psid_len))do { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid << " for a specified PSID length " <<
static_cast<unsigned>(psid_len); throw BadDataTypeCast
("../../../src/lib/dhcp/option_data_types.cc", 561, oss__.str
().c_str()); } while (1)
;
562 }
563
564 // All is good, so we can convert the PSID value read from the buffer to
565 // the port set number.
566 if (psid_len == 0) {
567 // Shift by 16 always gives zero (CID 1398333)
568 psid = 0;
569 } else {
570 psid >>= (sizeof(psid) * 8 - psid_len);
571 }
572 return (std::make_pair(PSIDLen(psid_len), PSID(psid)));
573}
574
575void
576OptionDataTypeUtil::writePsid(const PSIDLen& psid_len, const PSID& psid,
577 std::vector<uint8_t>& buf) {
578 if (psid_len.asUint8() > (sizeof(psid) * 8)) {
579 isc_throw(BadDataTypeCast, "invalid PSID length value "do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 581, oss__.str().c_str()); } while (1)
580 << psid_len.asUnsigned()do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 581, oss__.str().c_str()); } while (1)
581 << ", this value is expected to be in range of 0 to 16")do { std::ostringstream oss__; oss__ << "invalid PSID length value "
<< psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16"
; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 581, oss__.str().c_str()); } while (1)
;
582 }
583
584 if ((psid_len.asUint8() > 0) &&
585 (psid.asUint16() > (0xFFFF >> (sizeof(uint16_t) * 8 - psid_len.asUint8())))) {
586 isc_throw(BadDataTypeCast, "invalid PSID value " << psid.asUint16()do { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid.asUint16() << " for a specified PSID length "
<< psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 588, oss__.str().c_str()); } while (1)
587 << " for a specified PSID length "do { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid.asUint16() << " for a specified PSID length "
<< psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 588, oss__.str().c_str()); } while (1)
588 << psid_len.asUnsigned())do { std::ostringstream oss__; oss__ << "invalid PSID value "
<< psid.asUint16() << " for a specified PSID length "
<< psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc"
, 588, oss__.str().c_str()); } while (1)
;
589 }
590
591 buf.resize(buf.size() + 3);
592 buf.at(buf.size() - 3) = psid_len.asUint8();
593 isc::util::writeUint16(static_cast<uint16_t>
594 (psid.asUint16() << (sizeof(uint16_t) * 8 - psid_len.asUint8())),
595 &buf[buf.size() - 2], 2);
596}
597
598std::string
599OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) {
600 std::string value;
601 if (!buf.empty()) {
602 // Per RFC 2132, section 2 we need to drop trailing NULLs
603 auto begin = buf.begin();
604 auto end = util::str::seekTrimmed(begin, buf.end(), 0x0);
605 if (std::distance(begin, end) == 0) {
606 isc_throw(isc::OutOfRange, "string value carried by the option "do { std::ostringstream oss__; oss__ << "string value carried by the option "
"contained only NULLs"; throw isc::OutOfRange("../../../src/lib/dhcp/option_data_types.cc"
, 607, oss__.str().c_str()); } while (1)
607 "contained only NULLs")do { std::ostringstream oss__; oss__ << "string value carried by the option "
"contained only NULLs"; throw isc::OutOfRange("../../../src/lib/dhcp/option_data_types.cc"
, 607, oss__.str().c_str()); } while (1)
;
608 }
609
610 value.insert(value.end(), begin, end);
611 }
612
613 return (value);
614}
615
616void
617OptionDataTypeUtil::writeString(const std::string& value,
618 std::vector<uint8_t>& buf) {
619 if (value.size() > 0) {
620 buf.insert(buf.end(), value.begin(), value.end());
621 }
622}
623
624} // end of isc::dhcp namespace
625} // end of isc namespace