Kea: simple_parser.cc Source File

| Kea 3.0.3-git

lib/cc/simple_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2016-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 <cc/simple_parser.h>
10#include <asiolink/io_address.h>
11#include <boost/lexical_cast.hpp>
12#include <cc/data.h>
13#include <string>
14
15using namespace std;
16using namespace isc::asiolink;
17using namespace isc::dhcp;
18using isc::dhcp::DhcpConfigError;
19
20namespace isc {
21namespace data {
22
23void
24SimpleParser::checkRequired(const SimpleRequiredKeywords& required,
25 ConstElementPtr scope) {
26 for (auto const& name : required) {
27 if (scope->contains(name)) {
28 continue;
29 }
30 isc_throw(DhcpConfigError, "missing '" << name << "' parameter");
31 }
32}
33
34void
35SimpleParser::checkKeywords(const SimpleKeywords& keywords,
36 ConstElementPtr scope) {
37 string spurious;
38 for (auto const& entry : scope->mapValue()) {
39 if (keywords.count(entry.first) == 0) {
40 if (spurious.empty()) {
41 spurious = entry.first;
42 }
43 continue;
44 }
45 Element::types expected = keywords.at(entry.first);
46 if ((expected == Element::any) ||
47 (entry.second->getType() == expected)) {
48 continue;
49 }
50 isc_throw(DhcpConfigError, "'" << entry.first << "' parameter is not "
51 << (expected == Element::integer ? "an " : "a ")
52 << Element::typeToName(expected));
53 }
54 if (!spurious.empty()) {
55 isc_throw(DhcpConfigError, "spurious '" << spurious << "' parameter");
56 }
57}
58
59std::string
60SimpleParser::getString(ConstElementPtr scope, const std::string& name) {
61 ConstElementPtr x = scope->get(name);
62 if (!x) {
63 isc_throw(DhcpConfigError,
64 "missing parameter '" << name << "' ("
65 << scope->getPosition() << ")");
66 }
67 if (x->getType() != Element::string) {
68 isc_throw(DhcpConfigError,
69 "invalid type specified for parameter '" << name
70 << "' (" << x->getPosition() << ")");
71 }
72
73 return (x->stringValue());
74}
75
76int64_t
77SimpleParser::getInteger(ConstElementPtr scope, const std::string& name) {
78 ConstElementPtr x = scope->get(name);
79 if (!x) {
80 isc_throw(DhcpConfigError,
81 "missing parameter '" << name << "' ("
82 << scope->getPosition() << ")");
83 }
84 if (x->getType() != Element::integer) {
85 isc_throw(DhcpConfigError,
86 "invalid type specified for parameter '" << name
87 << "' (" << x->getPosition() << ")");
88 }
89
90 return (x->intValue());
91}
92
93int64_t
94 SimpleParser::getInteger(isc::data::ConstElementPtr scope, const std::string& name,
95 int64_t min, int64_t max) {
96 int64_t tmp = getInteger(scope, name);
97 if (tmp < min || tmp > max) {
98 isc_throw(OutOfRange,
99 "The '" << name << "' value (" << tmp
100 << ") is not within expected range: (" << min << " - " << max
101 << ")");
102 }
103
104 return (tmp);
105}
106
107bool
108SimpleParser::getBoolean(ConstElementPtr scope, const std::string& name) {
109 ConstElementPtr x = scope->get(name);
110 if (!x) {
111 isc_throw(DhcpConfigError,
112 "missing parameter '" << name << "' ("
113 << scope->getPosition() << ")");
114 }
115 if (x->getType() != Element::boolean) {
116 isc_throw(DhcpConfigError,
117 "invalid type specified for parameter '" << name
118 << "' (" << x->getPosition() << ")");
119 }
120
121 return (x->boolValue());
122}
123
124 IOAddress
125SimpleParser::getAddress(const ConstElementPtr& scope,
126 const std::string& name) {
127 std::string str = getString(scope, name);
128 try {
129 return (IOAddress(str));
130 } catch (const std::exception& e) {
131 isc_throw(DhcpConfigError, "Failed to convert '" << str
132 << "' to address: " << e.what() << "("
133 << getPosition(name, scope) << ")");
134 }
135}
136
137double
138SimpleParser::getDouble(const ConstElementPtr& scope,
139 const std::string& name) {
140 ConstElementPtr x = scope->get(name);
141 if (!x) {
142 isc_throw(DhcpConfigError,
143 "missing parameter '" << name << "' ("
144 << scope->getPosition() << ")");
145 }
146
147 if (x->getType() != Element::real) {
148 isc_throw(DhcpConfigError,
149 "invalid type specified for parameter '" << name
150 << "' (" << x->getPosition() << ")");
151 }
152
153 return (x->doubleValue());
154}
155
156
157const data::Element::Position&
158SimpleParser::getPosition(const std::string& name, const data::ConstElementPtr parent) {
159 if (!parent) {
160 return (data::Element::ZERO_POSITION());
161 }
162 ConstElementPtr elem = parent->get(name);
163 if (!elem) {
164 return (parent->getPosition());
165 }
166
167 return (elem->getPosition());
168}
169
170 size_t SimpleParser::setDefaults(ElementPtr scope,
171 const SimpleDefaults& default_values) {
172 size_t cnt = 0;
173
174 // This is the position representing a default value. As the values
175 // we're inserting here are not present in whatever the config file
176 // came from, we need to make sure it's clearly labeled as default.
177 const Element::Position pos("<default-value>", 0, 0);
178
179 // Let's go over all parameters we have defaults for.
180 for (auto const& def_value : default_values) {
181
182 // Try if such a parameter is there. If it is, let's
183 // skip it, because user knows best *cough*.
184 ConstElementPtr x = scope->get(string(def_value.name_));
185 if (x) {
186 // There is such a value already, skip it.
187 continue;
188 }
189
190 // There isn't such a value defined, let's create the default
191 // value...
192 switch (def_value.type_) {
193 case Element::string: {
194 x.reset(new StringElement(def_value.value_, pos));
195 break;
196 }
197 case Element::integer: {
198 try {
199 int int_value = boost::lexical_cast<int>(def_value.value_);
200 x.reset(new IntElement(int_value, pos));
201 }
202 catch (const std::exception& ex) {
203 isc_throw(BadValue, "Internal error. Integer value expected for: "
204 << def_value.name_ << ", value is: "
205 << def_value.value_ );
206 }
207
208 break;
209 }
210 case Element::boolean: {
211 bool bool_value;
212 if (def_value.value_ == string("true")) {
213 bool_value = true;
214 } else if (def_value.value_ == string("false")) {
215 bool_value = false;
216 } else {
217 isc_throw(DhcpConfigError,
218 "Internal error. Boolean value specified as "
219 << def_value.value_ << ", expected true or false");
220 }
221 x.reset(new BoolElement(bool_value, pos));
222 break;
223 }
224 case Element::real: {
225 double dbl_value = boost::lexical_cast<double>(def_value.value_);
226 x.reset(new DoubleElement(dbl_value, pos));
227 break;
228 }
229 default:
230 // No default values for null, list or map
231 isc_throw(DhcpConfigError,
232 "Internal error. Incorrect default value type.");
233 }
234
235 // ... and insert it into the provided Element tree.
236 scope->set(def_value.name_, x);
237 ++cnt;
238 }
239
240 return (cnt);
241}
242
243size_t
244SimpleParser::setListDefaults(ConstElementPtr list,
245 const SimpleDefaults& default_values) {
246 size_t cnt = 0;
247 for (auto const& entry : list->listValue()) {
248 cnt += setDefaults(entry, default_values);
249 }
250 return (cnt);
251}
252
253size_t
254SimpleParser::deriveParams(ConstElementPtr parent,
255 ElementPtr child,
256 const ParamsList& params) {
257 if ( (parent->getType() != Element::map) ||
258 (child->getType() != Element::map)) {
259 return (0);
260 }
261
262 size_t cnt = 0;
263 for (auto const& param : params) {
264 ConstElementPtr x = parent->get(param);
265 if (!x) {
266 // Parent doesn't define this parameter, so there's
267 // nothing to derive from
268 continue;
269 }
270
271 if (child->get(param)) {
272 // Child defines this parameter already. There's
273 // nothing to do here.
274 continue;
275 }
276
277 // Copy the parameters to the child scope.
278 child->set(param, x);
279 cnt++;
280 }
281
282 return (cnt);
283}
284
285const util::Triplet<uint32_t>
286SimpleParser::parseIntTriplet(const ConstElementPtr& scope,
287 const std::string& name) {
288 // Initialize as some compilers complain otherwise.
289 uint32_t value = 0;
290 bool has_value = false;
291 uint32_t min_value = 0;
292 bool has_min = false;
293 uint32_t max_value = 0;
294 bool has_max = false;
295 if (scope->contains(name)) {
296 value = getInteger(scope, name);
297 has_value = true;
298 }
299 if (scope->contains("min-" + name)) {
300 min_value = getInteger(scope, "min-" + name);
301 has_min = true;
302 }
303 if (scope->contains("max-" + name)) {
304 max_value = getInteger(scope, "max-" + name);
305 has_max = true;
306 }
307 if (!has_value && !has_min && !has_max) {
308 return (util::Triplet<uint32_t>());
309 }
310 if (has_value) {
311 if (!has_min && !has_max) {
312 // default only.
313 min_value = value;
314 max_value = value;
315 } else if (!has_min) {
316 // default and max.
317 min_value = value;
318 } else if (!has_max) {
319 // default and min.
320 max_value = value;
321 }
322 } else if (has_min) {
323 // min only.
324 if (!has_max) {
325 value = min_value;
326 max_value = min_value;
327 } else {
328 // min and max.
329 isc_throw(DhcpConfigError, "have min-" << name << " and max-"
330 << name << " but no " << name << " (default) in "
331 << scope->getPosition());
332 }
333 } else {
334 // max only.
335 min_value = max_value;
336 value = max_value;
337 }
338 // Check that min <= max.
339 if (min_value > max_value) {
340 if (has_min && has_max) {
341 isc_throw(DhcpConfigError, "the value of min-" << name << " ("
342 << min_value << ") is not less than max-" << name << " ("
343 << max_value << ")");
344 } else if (has_min) {
345 // Only min and default so min > default.
346 isc_throw(DhcpConfigError, "the value of min-" << name << " ("
347 << min_value << ") is not less than (default) " << name
348 << " (" << value << ")");
349 } else {
350 // Only default and max so default > max.
351 isc_throw(DhcpConfigError, "the value of (default) " << name
352 << " (" << value << ") is not less than max-" << name
353 << " (" << max_value << ")");
354 }
355 }
356 // Check that value is between min and max.
357 if ((value < min_value) || (value > max_value)) {
358 isc_throw(DhcpConfigError, "the value of (default) " << name << " ("
359 << value << ") is not between min-" << name << " ("
360 << min_value << ") and max-" << name << " ("
361 << max_value << ")");
362 }
363
364 return (util::Triplet<uint32_t>(min_value, value, max_value));
365}
366
367} // end of isc::dhcp namespace
368} // end of isc namespace
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition exceptions/exceptions.h:115
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:45
isc::data::BoolElement
Definition data.h:858
isc::data::DoubleElement
Definition data.h:841
isc::data::Element::typeToName
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
Definition data.cc:709
isc::data::Element::ZERO_POSITION
static const Position & ZERO_POSITION()
Returns Position object with line_ and pos_ set to 0, and with an empty file name.
Definition data.h:139
isc::data::Element::types
types
The types that an Element can hold.
Definition data.h:152
isc::data::Element::real
@ real
Definition data.h:154
isc::data::Element::map
@ map
Definition data.h:160
isc::data::Element::integer
@ integer
Definition data.h:153
isc::data::Element::any
@ any
Definition data.h:161
isc::data::Element::boolean
@ boolean
Definition data.h:155
isc::data::Element::string
@ string
Definition data.h:157
isc::data::IntElement
Notes: IntElement type is changed to int64_t.
Definition data.h:776
isc::data::SimpleParser::checkKeywords
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
Definition lib/cc/simple_parser.cc:35
isc::data::SimpleParser::setListDefaults
static size_t setListDefaults(isc::data::ConstElementPtr list, const SimpleDefaults &default_values)
Sets the default values for all entries in a list.
Definition lib/cc/simple_parser.cc:244
isc::data::SimpleParser::getPosition
static const data::Element::Position & getPosition(const std::string &name, const data::ConstElementPtr parent)
Utility method that returns position of an element.
Definition lib/cc/simple_parser.cc:158
isc::data::SimpleParser::getDouble
static double getDouble(const ConstElementPtr &scope, const std::string &name)
Returns a floating point parameter from a scope.
Definition lib/cc/simple_parser.cc:138
isc::data::SimpleParser::checkRequired
static void checkRequired(const SimpleRequiredKeywords &required, isc::data::ConstElementPtr scope)
Checks that all required keywords are present.
Definition lib/cc/simple_parser.cc:24
isc::data::SimpleParser::getAddress
static isc::asiolink::IOAddress getAddress(const ConstElementPtr &scope, const std::string &name)
Returns a IOAddress parameter from a scope.
Definition lib/cc/simple_parser.cc:125
isc::data::SimpleParser::getString
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
Definition lib/cc/simple_parser.cc:60
isc::data::SimpleParser::parseIntTriplet
const isc::util::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
Definition lib/cc/simple_parser.cc:286
isc::data::SimpleParser::getBoolean
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
Definition lib/cc/simple_parser.cc:108
isc::data::SimpleParser::deriveParams
static size_t deriveParams(isc::data::ConstElementPtr parent, isc::data::ElementPtr child, const ParamsList &params)
Derives (inherits) parameters from parent scope to a child.
Definition lib/cc/simple_parser.cc:254
isc::data::SimpleParser::getInteger
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
Definition lib/cc/simple_parser.cc:77
isc::data::SimpleParser::setDefaults
static size_t setDefaults(isc::data::ElementPtr scope, const SimpleDefaults &default_values)
Sets the default values.
Definition lib/cc/simple_parser.cc:170
isc::data::StringElement
Definition data.h:885
isc::dhcp::DhcpConfigError
To be removed. Please use ConfigError instead.
Definition dhcp_config_error.h:58
isc::util::Triplet
This template specifies a parameter value.
Definition triplet.h:37
data.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
io_address.h
simple_parser.h
isc::asiolink
Definition addr_utilities.cc:170
isc::data
Definition base_stamped_element.cc:12
isc::data::SimpleRequiredKeywords
std::vector< std::string > SimpleRequiredKeywords
This specifies all required keywords.
Definition lib/cc/simple_parser.h:33
isc::data::ParamsList
std::vector< std::string > ParamsList
This defines a list of all parameters that are derived (or inherited) between contexts.
Definition lib/cc/simple_parser.h:43
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::data::SimpleDefaults
std::vector< SimpleDefault > SimpleDefaults
This specifies all default values in a given scope (e.g. a subnet).
Definition lib/cc/simple_parser.h:39
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
isc::data::SimpleKeywords
std::map< std::string, isc::data::Element::types > SimpleKeywords
This specifies all accepted keywords with their types.
Definition lib/cc/simple_parser.h:36
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::util::str
Definition str.cc:29
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
isc::data::Element::Position
Represents the position of the data element within a configuration string.
Definition data.h:107