Kea 2.0.2
lib/cc/simple_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2021 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 return (tmp);
105}
106
107bool
108SimpleParser::getBoolean(ConstElementPtr scope, const std::string& name) {
109 ConstElementPtr x = scope->get(name);
110 if (!x) {
112 "missing parameter '" << name << "' ("
113 << scope->getPosition() << ")");
114 }
115 if (x->getType() != Element::boolean) {
117 "invalid type specified for parameter '" << name
118 << "' (" << x->getPosition() << ")");
119 }
120
121 return (x->boolValue());
122}
123
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
139 const std::string& name) {
140 ConstElementPtr x = scope->get(name);
141 if (!x) {
143 "missing parameter '" << name << "' ("
144 << scope->getPosition() << ")");
145 }
146
147 if (x->getType() != Element::real) {
149 "invalid type specified for parameter '" << name
150 << "' (" << x->getPosition() << ")");
151 }
152
153 return (x->doubleValue());
154}
155
156
158SimpleParser::getPosition(const std::string& name, const data::ConstElementPtr parent) {
159 if (!parent) {
161 }
162 ConstElementPtr elem = parent->get(name);
163 if (!elem) {
164 return (parent->getPosition());
165 }
166 return (elem->getPosition());
167}
168
170 const SimpleDefaults& default_values) {
171 size_t cnt = 0;
172
173 // This is the position representing a default value. As the values
174 // we're inserting here are not present in whatever the config file
175 // came from, we need to make sure it's clearly labeled as default.
176 const Element::Position pos("<default-value>", 0, 0);
177
178 // Let's go over all parameters we have defaults for.
179 BOOST_FOREACH(SimpleDefault def_value, default_values) {
180
181 // Try if such a parameter is there. If it is, let's
182 // skip it, because user knows best *cough*.
183 ConstElementPtr x = scope->get(string(def_value.name_));
184 if (x) {
185 // There is such a value already, skip it.
186 continue;
187 }
188
189 // There isn't such a value defined, let's create the default
190 // value...
191 switch (def_value.type_) {
192 case Element::string: {
193 x.reset(new StringElement(def_value.value_, pos));
194 break;
195 }
196 case Element::integer: {
197 try {
198 int int_value = boost::lexical_cast<int>(def_value.value_);
199 x.reset(new IntElement(int_value, pos));
200 }
201 catch (const std::exception& ex) {
202 isc_throw(BadValue, "Internal error. Integer value expected for: "
203 << def_value.name_ << ", value is: "
204 << def_value.value_ );
205 }
206
207 break;
208 }
209 case Element::boolean: {
210 bool bool_value;
211 if (def_value.value_ == string("true")) {
212 bool_value = true;
213 } else if (def_value.value_ == string("false")) {
214 bool_value = false;
215 } else {
217 "Internal error. Boolean value specified as "
218 << def_value.value_ << ", expected true or false");
219 }
220 x.reset(new BoolElement(bool_value, pos));
221 break;
222 }
223 case Element::real: {
224 double dbl_value = boost::lexical_cast<double>(def_value.value_);
225 x.reset(new DoubleElement(dbl_value, pos));
226 break;
227 }
228 default:
229 // No default values for null, list or map
231 "Internal error. Incorrect default value type.");
232 }
233
234 // ... and insert it into the provided Element tree.
235 scope->set(def_value.name_, x);
236 ++cnt;
237 }
238
239 return (cnt);
240}
241
242size_t
244 const SimpleDefaults& default_values) {
245 size_t cnt = 0;
246 BOOST_FOREACH(ElementPtr entry, list->listValue()) {
247 cnt += setDefaults(entry, default_values);
248 }
249 return (cnt);
250}
251
252size_t
254 ElementPtr child,
255 const ParamsList& params) {
256 if ( (parent->getType() != Element::map) ||
257 (child->getType() != Element::map)) {
258 return (0);
259 }
260
261 size_t cnt = 0;
262 BOOST_FOREACH(string param, params) {
263 ConstElementPtr x = parent->get(param);
264 if (!x) {
265 // Parent doesn't define this parameter, so there's
266 // nothing to derive from
267 continue;
268 }
269
270 if (child->get(param)) {
271 // Child defines this parameter already. There's
272 // nothing to do here.
273 continue;
274 }
275
276 // Copy the parameters to the child scope.
277 child->set(param, x);
278 cnt++;
279 }
280
281 return (cnt);
282}
283
286 const std::string& name) {
287 // Initialize as some compilers complain otherwise.
288 uint32_t value = 0;
289 bool has_value = false;
290 uint32_t min_value = 0;
291 bool has_min = false;
292 uint32_t max_value = 0;
293 bool has_max = false;
294 if (scope->contains(name)) {
295 value = getInteger(scope, name);
296 has_value = true;
297 }
298 if (scope->contains("min-" + name)) {
299 min_value = getInteger(scope, "min-" + name);
300 has_min = true;
301 }
302 if (scope->contains("max-" + name)) {
303 max_value = getInteger(scope, "max-" + name);
304 has_max = true;
305 }
306 if (!has_value && !has_min && !has_max) {
307 return (Triplet<uint32_t>());
308 }
309 if (has_value) {
310 if (!has_min && !has_max) {
311 // default only.
312 min_value = value;
313 max_value = value;
314 } else if (!has_min) {
315 // default and max.
316 min_value = value;
317 } else if (!has_max) {
318 // default and min.
319 max_value = value;
320 }
321 } else if (has_min) {
322 // min only.
323 if (!has_max) {
324 value = min_value;
325 max_value = min_value;
326 } else {
327 // min and max.
328 isc_throw(DhcpConfigError, "have min-" << name << " and max-"
329 << name << " but no " << name << " (default) in "
330 << scope->getPosition());
331 }
332 } else {
333 // max only.
334 min_value = max_value;
335 value = max_value;
336 }
337 // Check that min <= max.
338 if (min_value > max_value) {
339 if (has_min && has_max) {
340 isc_throw(DhcpConfigError, "the value of min-" << name << " ("
341 << min_value << ") is not less than max-" << name << " ("
342 << max_value << ")");
343 } else if (has_min) {
344 // Only min and default so min > default.
345 isc_throw(DhcpConfigError, "the value of min-" << name << " ("
346 << min_value << ") is not less than (default) " << name
347 << " (" << value << ")");
348 } else {
349 // Only default and max so default > max.
350 isc_throw(DhcpConfigError, "the value of (default) " << name
351 << " (" << value << ") is not less than max-" << name
352 << " (" << max_value << ")");
353 }
354 }
355 // Check that value is between min and max.
356 if ((value < min_value) || (value > max_value)) {
357 isc_throw(DhcpConfigError, "the value of (default) " << name << " ("
358 << value << ") is not between min-" << name << " ("
359 << min_value << ") and max-" << name << " ("
360 << max_value << ")");
361 }
362 return (Triplet<uint32_t>(min_value, value, max_value));
363}
364
365}; // end of isc::dhcp namespace
366}; // 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...
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
Definition: data.cc:616
static const Position & ZERO_POSITION()
Returns Position object with line_ and pos_ set to 0, and with an empty file name.
Definition: data.h:124
Notes: IntElement type is changed to int64_t.
Definition: data.h:588
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
const dhcp::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
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.
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:27
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:24
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:92
This array defines a single entry of default values.
const isc::data::Element::types type_