Kea 2.7.5
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;
19
20namespace isc {
21namespace data {
22
23void
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
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) {
64 "missing parameter '" << name << "' ("
65 << scope->getPosition() << ")");
66 }
67 if (x->getType() != Element::string) {
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) {
81 "missing parameter '" << name << "' ("
82 << scope->getPosition() << ")");
83 }
84 if (x->getType() != Element::integer) {
86 "invalid type specified for parameter '" << name
87 << "' (" << x->getPosition() << ")");
88 }
89
90 return (x->intValue());
91}
92
93int64_t
95 int64_t min, int64_t max) {
96 int64_t tmp = getInteger(scope, name);
97 if (tmp < min || tmp > max) {
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) {
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
167 return (elem->getPosition());
168}
169
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 {
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
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
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
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
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
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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: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
types
The types that an Element can hold.
Definition data.h:139
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.
This template specifies a parameter value.
Definition triplet.h:37
#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