1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef SIMPLE_PARSER_H
#define SIMPLE_PARSER_H
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <cc/dhcp_config_error.h>
#include <vector>
#include <string>
#include <stdint.h>
#include <limits>
namespace isc {
namespace data {
/// This array defines a single entry of default values
struct SimpleDefault {
SimpleDefault(const char* name, isc::data::Element::types type, const char* value)
:name_(name), type_(type), value_(value) {}
std::string name_;
const isc::data::Element::types type_;
const char* value_;
};
/// This specifies all default values in a given scope (e.g. a subnet)
typedef std::vector<SimpleDefault> SimpleDefaults;
/// This defines a list of all parameters that are derived (or inherited) between
/// contexts
typedef std::vector<std::string> ParamsList;
/// @brief A simple parser
///
/// This class is intended to be a simpler replacement for @ref
/// isc::dhcp::DhcpConfigParser. This class has been initially created to
/// facilitate DHCPv4 and DHCPv6 servers' configuration parsing. Thus examples
/// provided herein are related to DHCP configuration. Nevertheless, this is a
/// generic class to be used in other modules too.
///
/// The simplification comes from several factors:
/// - no build/commit nonsense. There's a single step:
/// CfgStorage parse(ConstElementPtr json)
/// that converts JSON configuration into an object and returns it.
/// - no state kept. This greatly simplifies the parsers (no contexts, no child
/// parsers list, no separate storage for uint32, strings etc. In fact,
/// this base class is purely static. However, some derived classes may store
/// some state. Implementors are advised to store as little state as possible.
/// - no optional parameters (all are mandatory). This simplifies the parser,
/// but introduces a new step before parsing where we insert the default
/// values into client configuration before parsing. This is actually a good
/// thing, because we now have a clear picture of the default parameters as
/// they're defined in a single place (the DhcpConfigParser had the defaults
/// spread out in multiple files in multiple directories).
class SimpleParser {
public:
/// @brief Derives (inherits) parameters from parent scope to a child
///
/// This method derives parameters from the parent scope to the child,
/// if there are no values specified in the child scope. For example,
/// this method can be used to derive timers from global scope (e.g. for
/// the whole DHCPv6 server) to a subnet scope. This method checks
/// if the child scope doesn't have more specific values defined. If
/// it doesn't, then the value from parent scope is copied over.
///
/// @param parent scope to copy from (e.g. global)
/// @param child scope to copy from (e.g. subnet)
/// @param params names of the parameters to copy
/// @return number of parameters copied
static size_t deriveParams(isc::data::ConstElementPtr parent,
isc::data::ElementPtr child,
const ParamsList& params);
/// @brief Sets the default values
///
/// This method sets the default values for parameters that are not
/// defined. The list of default values is specified by default_values.
/// If not present, those will be inserted into the scope. If
/// a parameter is already present, the default value will not
/// be inserted.
///
/// @param scope default values will be inserted here
/// @param default_values list of default values
/// @return number of parameters inserted
static size_t setDefaults(isc::data::ElementPtr scope,
const SimpleDefaults& default_values);
/// @brief Sets the default values for all entries in a list
///
/// This is a simple utility method that iterates over all
/// parameters in a list and calls setDefaults for each
/// entry.
///
/// @param list list to be iterated over
/// @param default_values list of default values
/// @return number of parameters inserted
static size_t setListDefaults(isc::data::ConstElementPtr list,
const SimpleDefaults& default_values);
/// @brief Utility method that returns position of an element
///
/// It's mostly useful for logging. If the element is missing
/// the parent position is returned or ZERO_POSITION if parent
/// is null.
///
/// @param name position of that element will be returned
/// @param parent parent element (optional)
/// @return position of the element specified.
static const data::Element::Position&
getPosition(const std::string& name, const data::ConstElementPtr parent);
/// @brief Returns a string parameter from a scope
///
/// Unconditionally returns a parameter.
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return a string value of the parameter
/// @throw DhcpConfigError if the parameter is not there or is not of
/// appropriate type
static std::string getString(isc::data::ConstElementPtr scope,
const std::string& name);
/// @brief Returns an integer parameter from a scope
///
/// Unconditionally returns a parameter.
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return an integer value of the parameter
/// @throw DhcpConfigError if the parameter is not there or is not of
/// appropriate type
static int64_t getInteger(isc::data::ConstElementPtr scope,
const std::string& name);
/// @brief Returns a boolean parameter from a scope
///
/// Unconditionally returns a parameter.
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return a boolean value of the parameter
/// @throw DhcpConfigError if the parameter is not there or is not of
/// appropriate type
static bool getBoolean(isc::data::ConstElementPtr scope,
const std::string& name);
/// @brief Returns a IOAddress parameter from a scope
///
/// Unconditionally returns a parameter.
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return an IOAddress representing the value of the parameter
/// @throw DhcpConfigError if the parameter is not there or is not of
/// appropriate type (or its conversion to IOAddress fails due to not
/// being a proper address).
static isc::asiolink::IOAddress
getAddress(const ConstElementPtr& scope, const std::string& name);
protected:
/// @brief Returns an integer value with range checking from a scope
///
/// This template should be instantiated in parsers when useful
///
/// @tparam int_type the integer type e.g. uint32_t
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter for error report
/// @return a value of int_type
/// @throw DhcpConfigError if the parameter is not there, is not of
/// appropriate type or is out of type value range
template <typename int_type> int_type
getIntType(isc::data::ConstElementPtr scope,
const std::string& name) {
int64_t val_int = getInteger(scope, name);
if ((val_int < std::numeric_limits<int_type>::min()) ||
(val_int > std::numeric_limits<int_type>::max())) {
isc_throw(isc::dhcp::DhcpConfigError,
"out of range value (" << val_int
<< ") specified for parameter '" << name
<< "' (" << getPosition(name, scope) << ")");
}
return (static_cast<int_type>(val_int));
}
/// @brief Returns a converted value from a scope
///
/// This template should be instantiated in parsers when useful
///
/// @tparam target_type the type of the result
/// @tparam convert the conversion function std::string -> target_type
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter for error report
/// @param type_name name of target_type for error report
/// @return a converted value of target_type
/// @throw DhcpConfigError if the parameter is not there, is not of
/// appropriate type or can not be converted
template <typename target_type,
target_type convert(const std::string&)> target_type
getAndConvert(isc::data::ConstElementPtr scope,
const std::string& name,
const std::string& type_name) {
std::string str = getString(scope, name);
try {
return (convert(str));
} catch (const std::exception&) {
isc_throw(isc::dhcp::DhcpConfigError,
"invalid " << type_name << " (" << str
<< ") specified for parameter '" << name
<< "' (" << getPosition(name, scope) << ")");
}
}
public:
/// @brief Returns a value converted to uint32_t
///
/// Instantiation of getIntType() to uint32_t
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return an uint32_t value
/// @throw isc::dhcp::DhcpConfigError when it is not an uint32_t
uint32_t getUint32(isc::data::ConstElementPtr scope,
const std::string& name) {
return (getIntType<uint32_t>(scope, name));
}
/// @brief Returns a value converted to uint16_t
///
/// Instantiation of getIntType() to uint16_t
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return an uint16_t value
/// @throw isc::dhcp::DhcpConfigError when it is not an uint16_t
uint16_t getUint16(isc::data::ConstElementPtr scope,
const std::string& name) {
return (getIntType<uint16_t>(scope, name));
}
/// @brief Get an uint8_t value
///
/// Instantiation of getIntType() to uint8_t
///
/// @param scope specified parameter will be extracted from this scope
/// @param name name of the parameter
/// @return uint8_t value
/// @throw isc::dhcp::DhcpConfigError when it is not an uint8_t
uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
return (getIntType<uint8_t>(scope, name));
}
};
};
};
#endif
|