blob: cd4838e6ffcba31ac285dbdd7ecb84e004216453 [file] [log] [blame]
dburgess82c46ff2011-10-07 02:40:51 +00001/*
2* Copyright 2009, 2010 Free Software Foundation, Inc.
kurtis.heimerldb70eb42012-12-16 06:06:32 +00003* Copyright 2010 Kestrel Signal Processing, Inc.
4* Copyright 2011, 2012 Range Networks, Inc.
dburgess82c46ff2011-10-07 02:40:51 +00005*
6* This software is distributed under the terms of the GNU Affero Public License.
7* See the COPYING file in the main directory for details.
8*
9* This use of this software may be subject to additional restrictions.
10* See the LEGAL file in the main directory for details.
11
12 This program is free software: you can redistribute it and/or modify
13 it under the terms of the GNU Affero General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU Affero General Public License for more details.
21
22 You should have received a copy of the GNU Affero General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24
25*/
26
27
28#ifndef CONFIGURATION_H
29#define CONFIGURATION_H
30
31
32#include "sqlite3util.h"
33
34#include <assert.h>
35#include <stdlib.h>
kurtis.heimerl5a872472013-05-31 21:47:25 +000036#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <regex.h>
dburgess82c46ff2011-10-07 02:40:51 +000039
40#include <map>
41#include <vector>
42#include <string>
kurtis.heimerl5a872472013-05-31 21:47:25 +000043#include <sstream>
dburgess82c46ff2011-10-07 02:40:51 +000044#include <iostream>
45
46#include <Threads.h>
47#include <stdint.h>
48
49
50/** A class for configuration file errors. */
51class ConfigurationTableError {};
kurtis.heimerlbcf60a82012-10-26 06:25:56 +000052extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it.
dburgess82c46ff2011-10-07 02:40:51 +000053
54/** An exception thrown when a given config key isn't found. */
55class ConfigurationTableKeyNotFound : public ConfigurationTableError {
56
57 private:
58
59 std::string mKey;
60
61 public:
62
63 ConfigurationTableKeyNotFound(const std::string& wKey)
64 :mKey(wKey)
kurtis.heimerlbcf60a82012-10-26 06:25:56 +000065 { }
dburgess82c46ff2011-10-07 02:40:51 +000066
67 const std::string& key() const { return mKey; }
68
69};
70
71
72class ConfigurationRecord {
73
74 private:
75
76 std::string mValue;
77 long mNumber;
78 bool mDefined;
79
80 public:
81
82 ConfigurationRecord(bool wDefined=true):
83 mDefined(wDefined)
84 { }
85
86 ConfigurationRecord(const std::string& wValue):
87 mValue(wValue),
88 mNumber(strtol(wValue.c_str(),NULL,0)),
89 mDefined(true)
90 { }
91
92 ConfigurationRecord(const char* wValue):
93 mValue(std::string(wValue)),
94 mNumber(strtol(wValue,NULL,0)),
95 mDefined(true)
96 { }
97
98
99 const std::string& value() const { return mValue; }
100 long number() const { return mNumber; }
101 bool defined() const { return mDefined; }
102
kurtis.heimerlbcf60a82012-10-26 06:25:56 +0000103 float floatNumber() const;
104
dburgess82c46ff2011-10-07 02:40:51 +0000105};
106
107
108/** A string class that uses a hash function for comparison. */
109class HashString : public std::string {
110
111
112 protected:
113
114 uint64_t mHash;
115
116 void computeHash();
117
118
119 public:
120
121 HashString(const char* src)
122 :std::string(src)
123 {
124 computeHash();
125 }
126
127 HashString(const std::string& src)
128 :std::string(src)
129 {
130 computeHash();
131 }
132
133 HashString()
134 {
135 mHash=0;
136 }
137
138 HashString& operator=(std::string& src)
139 {
140 std::string::operator=(src);
141 computeHash();
142 return *this;
143 }
144
145 HashString& operator=(const char* src)
146 {
147 std::string::operator=(src);
148 computeHash();
149 return *this;
150 }
151
152 bool operator==(const HashString& other)
153 {
154 return mHash==other.mHash;
155 }
156
157 bool operator<(const HashString& other)
158 {
159 return mHash<other.mHash;
160 }
161
162 bool operator>(const HashString& other)
163 {
164 return mHash<other.mHash;
165 }
166
167 uint64_t hash() const { return mHash; }
168
169};
170
171
kurtis.heimerl5a872472013-05-31 21:47:25 +0000172typedef std::map<std::string, ConfigurationRecord> ConfigurationRecordMap;
dburgess82c46ff2011-10-07 02:40:51 +0000173typedef std::map<HashString, ConfigurationRecord> ConfigurationMap;
kurtis.heimerl5a872472013-05-31 21:47:25 +0000174class ConfigurationKey;
175typedef std::map<std::string, ConfigurationKey> ConfigurationKeyMap;
dburgess82c46ff2011-10-07 02:40:51 +0000176
177/**
178 A class for maintaining a configuration key-value table,
179 based on sqlite3 and a local map-based cache.
180 Thread-safe, too.
181*/
182class ConfigurationTable {
183
184 private:
185
186 sqlite3* mDB; ///< database connection
187 ConfigurationMap mCache; ///< cache of recently access configuration values
188 mutable Mutex mLock; ///< control for multithreaded access to the cache
kurtis.heimerl5a872472013-05-31 21:47:25 +0000189 std::vector<std::string> (*mCrossCheck)(const std::string&); ///< cross check callback pointer
dburgess82c46ff2011-10-07 02:40:51 +0000190
191 public:
192
kurtis.heimerl5a872472013-05-31 21:47:25 +0000193 ConfigurationKeyMap mSchema;///< definition of configuration default values and validation logic
dburgess82c46ff2011-10-07 02:40:51 +0000194
kurtis.heimerl5a872472013-05-31 21:47:25 +0000195 ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, ConfigurationKeyMap wSchema = ConfigurationKeyMap());
196
197 /** Generate an up-to-date example sql file for new installs. */
198 std::string getDefaultSQL(const std::string& program, const std::string& version);
199
200 /** Generate an up-to-date TeX snippet. */
201 std::string getTeX(const std::string& program, const std::string& version);
dburgess82c46ff2011-10-07 02:40:51 +0000202
203 /** Return true if the key is used in the table. */
204 bool defines(const std::string& key);
205
kurtis.heimerl5a872472013-05-31 21:47:25 +0000206 /** Return true if the application's schema knows about this key. */
207 bool keyDefinedInSchema(const std::string& name);
dburgess82c46ff2011-10-07 02:40:51 +0000208
kurtis.heimerl5a872472013-05-31 21:47:25 +0000209 /** Return true if the provided value validates correctly against the defined schema. */
210 bool isValidValue(const std::string& name, const std::string& val);
211
212 /** Return true if the provided value validates correctly against the defined schema. */
213 bool isValidValue(const std::string& name, const int val) { std::stringstream ss; ss << val; return isValidValue(name, ss.str()); }
214
215 /** Return a map of all similar keys in the defined schema. */
216 ConfigurationKeyMap getSimilarKeys(const std::string& snippet);
217
218 /** Return true if this key is identified as static. */
219 bool isStatic(const std::string& key);
dburgess82c46ff2011-10-07 02:40:51 +0000220
221 /**
222 Get a string parameter from the table.
223 Throw ConfigurationTableKeyNotFound if not found.
224 */
225 std::string getStr(const std::string& key);
226
227
228 /**
kurtis.heimerl5a872472013-05-31 21:47:25 +0000229 Get a boolean from the table.
230 Return false if NULL or 0, true otherwise.
dburgess82c46ff2011-10-07 02:40:51 +0000231 */
kurtis.heimerl5a872472013-05-31 21:47:25 +0000232 bool getBool(const std::string& key);
dburgess82c46ff2011-10-07 02:40:51 +0000233
234 /**
235 Get a numeric parameter from the table.
236 Throw ConfigurationTableKeyNotFound if not found.
237 */
238 long getNum(const std::string& key);
239
240 /**
kurtis.heimerlbcf60a82012-10-26 06:25:56 +0000241 Get a vector of strings from the table.
242 */
243 std::vector<std::string> getVectorOfStrings(const std::string& key);
244
245 /**
kurtis.heimerlbcf60a82012-10-26 06:25:56 +0000246 Get a float from the table.
247 Throw ConfigurationTableKeyNotFound if not found.
248 */
249 float getFloat(const std::string& key);
250
251 /**
dburgess82c46ff2011-10-07 02:40:51 +0000252 Get a numeric vector from the table.
253 */
254 std::vector<unsigned> getVector(const std::string& key);
255
256 /** Get length of a vector */
257 unsigned getVectorLength(const std::string &key)
258 { return getVector(key).size(); }
259
260 /** Set or change a value in the table. */
261 bool set(const std::string& key, const std::string& value);
262
263 /** Set or change a value in the table. */
264 bool set(const std::string& key, long value);
265
266 /** Create an entry in the table, no value though. */
267 bool set(const std::string& key);
268
269 /**
kurtis.heimerlbcf60a82012-10-26 06:25:56 +0000270 Remove an entry from the table.
271 Will not alter required values.
272 @param key The key of the item to be removed.
273 @return true if anything was actually removed.
274 */
275 bool remove(const std::string& key);
276
dburgess82c46ff2011-10-07 02:40:51 +0000277 /** Search the table, dumping to a stream. */
278 void find(const std::string& pattern, std::ostream&) const;
279
kurtis.heimerl5a872472013-05-31 21:47:25 +0000280 /** Return all key/value pairs stored in the ConfigurationTable */
281 ConfigurationRecordMap getAllPairs() const;
282
dburgess82c46ff2011-10-07 02:40:51 +0000283 /** Define the callback to purge the cache whenever the database changes. */
284 void setUpdateHook(void(*)(void *,int ,char const *,char const *,sqlite3_int64));
285
kurtis.heimerl5a872472013-05-31 21:47:25 +0000286 /** Define the callback for cross checking. */
287 void setCrossCheckHook(std::vector<std::string> (*wCrossCheck)(const std::string&));
288
289 /** Execute the application specific value cross checking logic. */
290 std::vector<std::string> crossCheck(const std::string& key);
291
dburgess82c46ff2011-10-07 02:40:51 +0000292 /** purege cache if it exceeds a certain age */
293 void checkCacheAge();
294
295 /** Delete all records from the cache. */
296 void purge();
297
298
299 private:
300
301 /**
302 Attempt to lookup a record, cache if needed.
303 Throw ConfigurationTableKeyNotFound if not found.
304 Caller should hold mLock because the returned reference points into the cache.
305 */
306 const ConfigurationRecord& lookup(const std::string& key);
307
308};
309
310
kurtis.heimerlbcf60a82012-10-26 06:25:56 +0000311typedef std::map<HashString, std::string> HashStringMap;
312
313class SimpleKeyValue {
314
315 protected:
316
317 HashStringMap mMap;
318
319 public:
320
321 /** Take a C string "A=B" and set map["A"]="B". */
322 void addItem(const char*);
323
324 /** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */
325 void addItems(const char*s);
326
327 /** Return a reference to the string at map["key"]. */
328 const char* get(const char*) const;
329};
330
331
kurtis.heimerl5a872472013-05-31 21:47:25 +0000332class ConfigurationKey {
333
334 public:
335
336 enum VisibilityLevel
337 {
338 CUSTOMER,
339 CUSTOMERSITE,
340 CUSTOMERTUNE,
341 CUSTOMERWARN,
342 DEVELOPER,
343 FACTORY
344 };
345
346 enum Type
347 {
348 BOOLEAN,
349 CHOICE_OPT,
350 CHOICE,
351 CIDR_OPT,
352 CIDR,
353 FILEPATH_OPT,
354 FILEPATH,
355 IPADDRESS_OPT,
356 IPADDRESS,
357 IPANDPORT,
358 MIPADDRESS_OPT,
359 MIPADDRESS,
360 PORT_OPT,
361 PORT,
362 REGEX_OPT,
363 REGEX,
364 STRING_OPT,
365 STRING,
366 VALRANGE
367 };
368
369 private:
370
371 std::string mName;
372 std::string mDefaultValue;
373 std::string mUnits;
374 VisibilityLevel mVisibility;
375 Type mType;
376 std::string mValidValues;
377 bool mIsStatic;
378 std::string mDescription;
379
380
381 public:
382
383 ConfigurationKey(const std::string& wName, const std::string& wDefaultValue, const std::string& wUnits, const VisibilityLevel wVisibility, const Type wType, const std::string& wValidValues, bool wIsStatic, const std::string& wDescription):
384 mName(wName),
385 mDefaultValue(wDefaultValue),
386 mUnits(wUnits),
387 mVisibility(wVisibility),
388 mType(wType),
389 mValidValues(wValidValues),
390 mIsStatic(wIsStatic),
391 mDescription(wDescription)
392 { }
393
394 ConfigurationKey()
395 { }
396
397 const std::string& getName() const { return mName; }
398 const std::string& getDefaultValue() const { return mDefaultValue; }
399 void updateDefaultValue(const std::string& newValue) { mDefaultValue = newValue; }
400 void updateDefaultValue(const int newValue) { std::stringstream ss; ss << newValue; updateDefaultValue(ss.str()); }
401 const std::string& getUnits() const { return mUnits; }
402 const VisibilityLevel& getVisibility() const { return mVisibility; }
403 const Type& getType() const { return mType; }
404 const std::string& getValidValues() const { return mValidValues; }
405 bool isStatic() const { return mIsStatic; }
406 const std::string& getDescription() const { return mDescription; }
407
408 static bool isValidIP(const std::string& ip);
409 static void getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping);
410 template<class T> static bool isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger);
411 static const std::string visibilityLevelToString(const VisibilityLevel& visibility);
412 static const std::string typeToString(const ConfigurationKey::Type& type);
413 static void printKey(const ConfigurationKey &key, const std::string& currentValue, std::ostream& os);
414 static void printDescription(const ConfigurationKey &key, std::ostream& os);
415 static const std::string getARFCNsString();
416};
417
dburgess82c46ff2011-10-07 02:40:51 +0000418
419#endif
420
421
422// vim: ts=4 sw=4