File: | home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/dhcp/option_data_types.cc |
Warning: | line 465, column 30 The result of right shift is undefined because the right operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // Copyright (C) 2012-2024 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 | ||||
18 | using namespace isc::asiolink; | |||
19 | ||||
20 | namespace { | |||
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. | |||
26 | std::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 | ||||
34 | namespace isc { | |||
35 | namespace dhcp { | |||
36 | ||||
37 | OptionDataTypeUtil::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 | ||||
82 | OptionDataType | |||
83 | OptionDataTypeUtil::getDataType(const std::string& data_type) { | |||
84 | return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type)); | |||
85 | } | |||
86 | ||||
87 | OptionDataType | |||
88 | OptionDataTypeUtil::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 | ||||
97 | int | |||
98 | OptionDataTypeUtil::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 | ||||
128 | const std::string& | |||
129 | OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) { | |||
130 | return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type)); | |||
131 | } | |||
132 | ||||
133 | const std::string& | |||
134 | OptionDataTypeUtil::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 | ||||
143 | OptionDataTypeUtil& | |||
144 | OptionDataTypeUtil::instance() { | |||
145 | static OptionDataTypeUtil instance; | |||
146 | return (instance); | |||
147 | } | |||
148 | ||||
149 | asiolink::IOAddress | |||
150 | OptionDataTypeUtil::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("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("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("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("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("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("option_data_types.cc", 167, oss__.str().c_str ()); } while (1); | |||
168 | } | |||
169 | } | |||
170 | ||||
171 | void | |||
172 | OptionDataTypeUtil::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 | ||||
178 | void | |||
179 | OptionDataTypeUtil::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("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("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 | ||||
196 | OpaqueDataTuple::LengthFieldType | |||
197 | OptionDataTypeUtil::getTupleLenFieldType(Option::Universe u) { | |||
198 | if (u == Option::V4) { | |||
199 | return (OpaqueDataTuple::LENGTH_1_BYTE); | |||
200 | } | |||
201 | return (OpaqueDataTuple::LENGTH_2_BYTES); | |||
202 | } | |||
203 | ||||
204 | std::string | |||
205 | OptionDataTypeUtil::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("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("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("option_data_types.cc", 211, oss__ .str().c_str()); } while (1); | |||
212 | } | |||
213 | uint8_t len = buf[0]; | |||
214 | if (buf.size() < 1 + 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("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("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("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("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("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("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 + 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("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("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("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("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("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("option_data_types.cc" , 242, oss__.str().c_str()); } while (1); | |||
243 | } | |||
244 | } | |||
245 | ||||
246 | void | |||
247 | OptionDataTypeUtil::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("option_data_types.cc", 252, oss__.str().c_str ()); } while (1); | |||
253 | } | |||
254 | } | |||
255 | ||||
256 | void | |||
257 | OptionDataTypeUtil::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 ("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 ("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 ("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 ("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 ("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 ("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("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("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("option_data_types.cc" , 280, oss__.str().c_str()); } while (1); | |||
281 | } | |||
282 | buf.insert(buf.end(), value.begin(), value.end()); | |||
283 | } | |||
284 | ||||
285 | void | |||
286 | OptionDataTypeUtil::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("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("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("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("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("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("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("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("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("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("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 | ||||
316 | bool | |||
317 | OptionDataTypeUtil::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("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("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("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("option_data_types.cc", 328 , oss__.str().c_str()); } while (1); | |||
329 | } | |||
330 | ||||
331 | void | |||
332 | OptionDataTypeUtil::writeBool(const bool value, | |||
333 | std::vector<uint8_t>& buf) { | |||
334 | buf.push_back(static_cast<uint8_t>(value ? 1 : 0)); | |||
335 | } | |||
336 | ||||
337 | std::string | |||
338 | OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf) { | |||
339 | // If buffer is empty emit an error. | |||
340 | if (buf.empty()) { | |||
341 | 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("option_data_types.cc" , 342, oss__.str().c_str()); } while (1) | |||
342 | << " The buffer is empty.")do { std::ostringstream oss__; oss__ << "unable to read FQDN from a buffer." << " The buffer is empty."; throw BadDataTypeCast("option_data_types.cc" , 342, oss__.str().c_str()); } while (1); | |||
343 | } | |||
344 | // Set up an InputBuffer so as we can use isc::dns::Name object to get the FQDN. | |||
345 | isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size()); | |||
346 | try { | |||
347 | // Try to create an object from the buffer. If exception is thrown | |||
348 | // it means that the buffer doesn't hold a valid domain name (invalid | |||
349 | // syntax). | |||
350 | isc::dns::Name name(in_buf); | |||
351 | return (name.toText()); | |||
352 | } catch (const isc::Exception& ex) { | |||
353 | // Unable to convert the data in the buffer into FQDN. | |||
354 | isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("option_data_types.cc", 354, oss__.str().c_str ()); } while (1); | |||
355 | } | |||
356 | } | |||
357 | ||||
358 | void | |||
359 | OptionDataTypeUtil::writeFqdn(const std::string& fqdn, | |||
360 | std::vector<uint8_t>& buf, | |||
361 | bool downcase) { | |||
362 | try { | |||
363 | isc::dns::Name name(fqdn, downcase); | |||
364 | isc::dns::LabelSequence labels(name); | |||
365 | if (labels.getDataLength() > 0) { | |||
366 | size_t read_len = 0; | |||
367 | const uint8_t* data = labels.getData(&read_len); | |||
368 | buf.insert(buf.end(), data, data + read_len); | |||
369 | } | |||
370 | } catch (const isc::Exception& ex) { | |||
371 | isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("option_data_types.cc", 371, oss__.str().c_str ()); } while (1); | |||
372 | } | |||
373 | } | |||
374 | ||||
375 | unsigned int | |||
376 | OptionDataTypeUtil::getLabelCount(const std::string& text_name) { | |||
377 | // The isc::dns::Name class doesn't accept empty names. However, in some | |||
378 | // cases we may be dealing with empty names (e.g. sent by the DHCP clients). | |||
379 | // Empty names should not be sent as hostnames but if they are, for some | |||
380 | // reason, we don't want to throw an exception from this function. We | |||
381 | // rather want to signal empty name by returning 0 number of labels. | |||
382 | if (text_name.empty()) { | |||
383 | return (0); | |||
384 | } | |||
385 | try { | |||
386 | isc::dns::Name name(text_name); | |||
387 | return (name.getLabelCount()); | |||
388 | } catch (const isc::Exception& ex) { | |||
389 | isc_throw(BadDataTypeCast, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("option_data_types.cc", 389, oss__.str().c_str ()); } while (1); | |||
390 | } | |||
391 | } | |||
392 | ||||
393 | PrefixTuple | |||
394 | OptionDataTypeUtil::readPrefix(const std::vector<uint8_t>& buf) { | |||
395 | // Prefix typically consists of the prefix length and the | |||
396 | // actual value. If prefix length is 0, the buffer length should | |||
397 | // be at least 1 byte to hold this length value. | |||
398 | if (buf.empty()) { | |||
| ||||
399 | 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("option_data_types.cc" , 400, oss__.str().c_str()); } while (1) | |||
400 | "a truncated buffer")do { std::ostringstream oss__; oss__ << "unable to read prefix length from " "a truncated buffer"; throw BadDataTypeCast("option_data_types.cc" , 400, oss__.str().c_str()); } while (1); | |||
401 | } | |||
402 | ||||
403 | // Surround everything with try-catch to unify exceptions being | |||
404 | // thrown by various functions and constructors. | |||
405 | try { | |||
406 | // Try to create PrefixLen object from the prefix length held | |||
407 | // in the buffer. This may cause an exception if the length is | |||
408 | // invalid (greater than 128). | |||
409 | PrefixLen prefix_len(buf.at(0)); | |||
410 | ||||
411 | // Convert prefix length to bytes, because we operate on bytes, | |||
412 | // rather than bits. | |||
413 | uint8_t prefix_len_bytes = (prefix_len.asUint8() / 8); | |||
414 | // Check if we need to zero pad any bits. This is the case when | |||
415 | // the prefix length is not divisible by 8 (bits per byte). The | |||
416 | // calculations below may require some explanations. We first | |||
417 | // perform prefix_len % 8 to get the number of useful bits beyond | |||
418 | // the current prefix_len_bytes value. By substracting it from 8 | |||
419 | // we get the number of zero padded bits, but with the special | |||
420 | // case of 8 when the result of substraction is 0. The value of | |||
421 | // 8 really means no padding so we make a modulo division once | |||
422 | // again to turn 8s to 0s. | |||
423 | const uint8_t zero_padded_bits = | |||
424 | static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8); | |||
425 | // If there are zero padded bits, it means that we need an extra | |||
426 | // byte to be retrieved from the buffer. | |||
427 | if (zero_padded_bits > 0) { | |||
428 | ++prefix_len_bytes; | |||
429 | } | |||
430 | ||||
431 | // Make sure that the buffer is long enough. We substract 1 to | |||
432 | // also account for the fact that the buffer includes a prefix | |||
433 | // length besides a prefix. | |||
434 | if ((buf.size() - 1) < prefix_len_bytes) { | |||
435 | 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("option_data_types.cc", 436, oss__.str ().c_str()); } while (1) | |||
436 | << 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("option_data_types.cc", 436, oss__.str ().c_str()); } while (1); | |||
437 | } | |||
438 | ||||
439 | // It is possible for a prefix to be zero if the prefix length | |||
440 | // is zero. | |||
441 | IOAddress prefix(IOAddress::IPV6_ZERO_ADDRESS()); | |||
442 | ||||
443 | // If there is anything more than prefix length is this buffer | |||
444 | // we need to read it. | |||
445 | if (buf.size() > 1) { | |||
446 | // Buffer has to be copied, because we will modify its | |||
447 | // contents by setting certain bits to 0, if necessary. | |||
448 | std::vector<uint8_t> prefix_buf(buf.begin() + 1, buf.end()); | |||
449 | // All further conversions require that the buffer length is | |||
450 | // 16 bytes. | |||
451 | if (prefix_buf.size() < V6ADDRESS_LEN) { | |||
452 | prefix_buf.resize(V6ADDRESS_LEN); | |||
453 | if (prefix_len_bytes < prefix_buf.size()) { | |||
454 | // Zero all bits in the buffer beyond prefix length | |||
455 | // position. | |||
456 | std::fill(prefix_buf.begin() + prefix_len_bytes, | |||
457 | prefix_buf.end(), 0); | |||
458 | ||||
459 | if (zero_padded_bits) { | |||
460 | // There is a byte that require zero padding. We | |||
461 | // achieve that by shifting the value of that byte | |||
462 | // back and forth by the number of zeroed bits. | |||
463 | prefix_buf.at(prefix_len_bytes - 1) = | |||
464 | (prefix_buf.at(prefix_len_bytes - 1) | |||
465 | >> zero_padded_bits) | |||
| ||||
466 | << zero_padded_bits; | |||
467 | } | |||
468 | } | |||
469 | } | |||
470 | // Convert the buffer to the IOAddress object. | |||
471 | prefix = IOAddress::fromBytes(AF_INET610, &prefix_buf[0]); | |||
472 | } | |||
473 | ||||
474 | return (std::make_pair(prefix_len, prefix)); | |||
475 | ||||
476 | } catch (const BadDataTypeCast& ex) { | |||
477 | // Pass through the BadDataTypeCast exceptions. | |||
478 | throw; | |||
479 | ||||
480 | } catch (const std::exception& ex) { | |||
481 | // If an exception of a different type has been thrown, insert | |||
482 | // a text that indicates that the failure occurred during reading | |||
483 | // the prefix and modify exception type to BadDataTypeCast. | |||
484 | 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("option_data_types.cc" , 485, oss__.str().c_str()); } while (1) | |||
485 | << ex.what())do { std::ostringstream oss__; oss__ << "unable to read a prefix from a buffer: " << ex.what(); throw BadDataTypeCast("option_data_types.cc" , 485, oss__.str().c_str()); } while (1); | |||
486 | } | |||
487 | } | |||
488 | ||||
489 | void | |||
490 | OptionDataTypeUtil::writePrefix(const PrefixLen& prefix_len, | |||
491 | const IOAddress& prefix, | |||
492 | std::vector<uint8_t>& buf) { | |||
493 | // Prefix must be an IPv6 prefix. | |||
494 | if (!prefix.isV6()) { | |||
495 | isc_throw(BadDataTypeCast, "illegal prefix value "do { std::ostringstream oss__; oss__ << "illegal prefix value " << prefix; throw BadDataTypeCast("option_data_types.cc" , 496, oss__.str().c_str()); } while (1) | |||
496 | << prefix)do { std::ostringstream oss__; oss__ << "illegal prefix value " << prefix; throw BadDataTypeCast("option_data_types.cc" , 496, oss__.str().c_str()); } while (1); | |||
497 | } | |||
498 | ||||
499 | // We don't need to validate the prefix_len value, because it is | |||
500 | // already validated by the PrefixLen class. | |||
501 | buf.push_back(prefix_len.asUint8()); | |||
502 | ||||
503 | // Convert the prefix length to a number of bytes. | |||
504 | uint8_t prefix_len_bytes = prefix_len.asUint8() / 8; | |||
505 | // Check if there are any bits that require zero padding. See the | |||
506 | // commentary in readPrefix to see how this is calculated. | |||
507 | const uint8_t zero_padded_bits = | |||
508 | static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8); | |||
509 | // If zero padding is needed it means that we need to extend the | |||
510 | // buffer to hold the "partially occupied" byte. | |||
511 | if (zero_padded_bits > 0) { | |||
512 | ++prefix_len_bytes; | |||
513 | } | |||
514 | ||||
515 | // Convert the prefix to byte representation and append it to | |||
516 | // our output buffer. | |||
517 | std::vector<uint8_t> prefix_bytes = prefix.toBytes(); | |||
518 | buf.insert(buf.end(), prefix_bytes.begin(), | |||
519 | prefix_bytes.begin() + prefix_len_bytes); | |||
520 | // If the last byte requires zero padding we achieve that by shifting | |||
521 | // bits back and forth by the number of insignificant bits. | |||
522 | if (zero_padded_bits) { | |||
523 | *buf.rbegin() = (*buf.rbegin() >> zero_padded_bits) << zero_padded_bits; | |||
524 | } | |||
525 | } | |||
526 | ||||
527 | PSIDTuple | |||
528 | OptionDataTypeUtil::readPsid(const std::vector<uint8_t>& buf) { | |||
529 | if (buf.size() < 3) { | |||
530 | 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 ("option_data_types.cc", 532, oss__.str().c_str()); } while ( 1) | |||
531 | << " 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 ("option_data_types.cc", 532, oss__.str().c_str()); } while ( 1) | |||
532 | << ". 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 ("option_data_types.cc", 532, oss__.str().c_str()); } while ( 1); | |||
533 | } | |||
534 | ||||
535 | // Read PSID length. | |||
536 | uint8_t psid_len = buf[0]; | |||
537 | ||||
538 | // PSID length must not be greater than 16 bits. | |||
539 | if (psid_len > (sizeof(uint16_t) * 8)) { | |||
540 | 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("option_data_types.cc", 542, oss__.str ().c_str()); } while (1) | |||
541 | << 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("option_data_types.cc", 542, oss__.str ().c_str()); } while (1) | |||
542 | << ", 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("option_data_types.cc", 542, oss__.str ().c_str()); } while (1); | |||
543 | } | |||
544 | ||||
545 | // Read two bytes of PSID value. | |||
546 | uint16_t psid = isc::util::readUint16(&buf[1], 2); | |||
547 | ||||
548 | // We need to check that the PSID value does not exceed the maximum value | |||
549 | // for a specified PSID length. That means that all bits placed further than | |||
550 | // psid_len from the left must be set to 0. | |||
551 | // The value 0 is a special case because the RFC explicitly says that the | |||
552 | // PSID value should be ignored if psid_len is 0. | |||
553 | if ((psid & ~psid_bitmask[psid_len]) != 0) { | |||
554 | 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 ("option_data_types.cc", 556, oss__.str().c_str()); } while ( 1) | |||
555 | << " 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 ("option_data_types.cc", 556, oss__.str().c_str()); } while ( 1) | |||
556 | << 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 ("option_data_types.cc", 556, oss__.str().c_str()); } while ( 1); | |||
557 | } | |||
558 | ||||
559 | // All is good, so we can convert the PSID value read from the buffer to | |||
560 | // the port set number. | |||
561 | if (psid_len == 0) { | |||
562 | // Shift by 16 always gives zero (CID 1398333) | |||
563 | psid = 0; | |||
564 | } else { | |||
565 | psid >>= (sizeof(psid) * 8 - psid_len); | |||
566 | } | |||
567 | return (std::make_pair(PSIDLen(psid_len), PSID(psid))); | |||
568 | } | |||
569 | ||||
570 | void | |||
571 | OptionDataTypeUtil::writePsid(const PSIDLen& psid_len, const PSID& psid, | |||
572 | std::vector<uint8_t>& buf) { | |||
573 | if (psid_len.asUint8() > (sizeof(psid) * 8)) { | |||
574 | 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("option_data_types.cc", 576, oss__.str ().c_str()); } while (1) | |||
575 | << 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("option_data_types.cc", 576, oss__.str ().c_str()); } while (1) | |||
576 | << ", 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("option_data_types.cc", 576, oss__.str ().c_str()); } while (1); | |||
577 | } | |||
578 | ||||
579 | if ((psid_len.asUint8() > 0) && | |||
580 | (psid.asUint16() > (0xFFFF >> (sizeof(uint16_t) * 8 - psid_len.asUint8())))) { | |||
581 | 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("option_data_types.cc" , 583, oss__.str().c_str()); } while (1) | |||
582 | << " 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("option_data_types.cc" , 583, oss__.str().c_str()); } while (1) | |||
583 | << psid_len.asUnsigned())do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid.asUint16() << " for a specified PSID length " << psid_len.asUnsigned(); throw BadDataTypeCast("option_data_types.cc" , 583, oss__.str().c_str()); } while (1); | |||
584 | } | |||
585 | ||||
586 | buf.resize(buf.size() + 3); | |||
587 | buf.at(buf.size() - 3) = psid_len.asUint8(); | |||
588 | isc::util::writeUint16(static_cast<uint16_t> | |||
589 | (psid.asUint16() << (sizeof(uint16_t) * 8 - psid_len.asUint8())), | |||
590 | &buf[buf.size() - 2], 2); | |||
591 | } | |||
592 | ||||
593 | std::string | |||
594 | OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) { | |||
595 | std::string value; | |||
596 | if (!buf.empty()) { | |||
597 | // Per RFC 2132, section 2 we need to drop trailing NULLs | |||
598 | auto begin = buf.begin(); | |||
599 | auto end = util::str::seekTrimmed(begin, buf.end(), 0x0); | |||
600 | if (std::distance(begin, end) == 0) { | |||
601 | 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("option_data_types.cc" , 602, oss__.str().c_str()); } while (1) | |||
602 | "contained only NULLs")do { std::ostringstream oss__; oss__ << "string value carried by the option " "contained only NULLs"; throw isc::OutOfRange("option_data_types.cc" , 602, oss__.str().c_str()); } while (1); | |||
603 | } | |||
604 | ||||
605 | value.insert(value.end(), begin, end); | |||
606 | } | |||
607 | ||||
608 | return (value); | |||
609 | } | |||
610 | ||||
611 | void | |||
612 | OptionDataTypeUtil::writeString(const std::string& value, | |||
613 | std::vector<uint8_t>& buf) { | |||
614 | if (value.size() > 0) { | |||
615 | buf.insert(buf.end(), value.begin(), value.end()); | |||
616 | } | |||
617 | } | |||
618 | ||||
619 | } // end of isc::dhcp namespace | |||
620 | } // end of isc namespace |