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