]> git.stg.codes - stg.git/blob - projects/stargazer/settings_impl.cpp
Merge branch 'stg-2.409-radius'
[stg.git] / projects / stargazer / settings_impl.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  */
20
21 #include "settings_impl.h"
22
23 #include "stg/logger.h"
24 #include "stg/dotconfpp.h"
25 #include "stg/common.h"
26
27 #include <stdexcept>
28 #include <cstring>
29 #include <cerrno>
30
31 namespace
32 {
33
34 struct Error : public std::runtime_error
35 {
36     Error(const std::string& message) : runtime_error(message) {}
37 };
38
39 std::vector<std::string> toValues(const DOTCONFDocumentNode& node)
40 {
41     std::vector<std::string> values;
42
43     size_t i = 0;
44     const char* value = NULL;
45     while ((value = node.getValue(i++)) != NULL)
46         values.push_back(value);
47
48     return values;
49 }
50
51 std::vector<PARAM_VALUE> toPVS(const DOTCONFDocumentNode& node)
52 {
53     std::vector<PARAM_VALUE> pvs;
54
55     const DOTCONFDocumentNode* child = node.getChildNode();
56     while (child != NULL)
57         {
58         if (child->getName() == NULL)
59             continue;
60
61         if (child->getChildNode() == NULL)
62             pvs.push_back(PARAM_VALUE(child->getName(), toValues(*child)));
63         else
64             pvs.push_back(PARAM_VALUE(child->getName(), toValues(*child), toPVS(*child)));
65
66         child = child->getNextNode();
67         }
68
69     return pvs;
70 }
71
72 unsigned toPeriod(const char* value)
73 {
74     if (value == NULL)
75         throw Error("No detail stat period value.");
76
77     std::string period(value);
78     if (period == "1")
79         return dsPeriod_1;
80     else if (period == "1/2")
81         return dsPeriod_1_2;
82     else if (period == "1/4")
83         return dsPeriod_1_4;
84     else if (period == "1/6")
85         return dsPeriod_1_6;
86
87     throw Error("Invalid detail stat period value: '" + period + "'. Should be one of '1', '1/2', '1/4' or '1/6'.");
88 }
89
90 }
91
92 //-----------------------------------------------------------------------------
93 SETTINGS_IMPL::SETTINGS_IMPL(const std::string & cd)
94     : modulesPath("/usr/lib/stg"),
95       dirName(DIR_NUM),
96       confDir(cd.empty() ? "/etc/stargazer" : cd),
97       scriptsDir(confDir),
98       rules(confDir + "/rules"),
99       logFile("/var/log/stargazer.log"),
100       pidFile("/var/run/stargazer.pid"),
101       monitorDir("/var/stargazer/monitoring"),
102       monitoring(false),
103       detailStatWritePeriod(dsPeriod_1_6),
104       statWritePeriod(10),
105       stgExecMsgKey(5555),
106       executersNum(1),
107       fullFee(false),
108       dayFee(0),
109       dayResetTraff(0),
110       spreadFee(false),
111       freeMbAllowInet(false),
112       dayFeeIsLastDay(false),
113       stopOnError(true),
114       writeFreeMbTraffCost(false),
115       showFeeInCash(true),
116       messageTimeout(0),
117       feeChargeType(0),
118       reconnectOnTariffChange(false),
119       disableSessionLog(false),
120       logger(GetStgLogger())
121 {
122     filterParamsLog.push_back("*");
123 }
124 //-----------------------------------------------------------------------------
125 SETTINGS_IMPL::SETTINGS_IMPL(const SETTINGS_IMPL & rval)
126     : modulesPath(rval.modulesPath),
127       dirName(rval.dirName),
128       confDir(rval.confDir),
129       scriptsDir(rval.scriptsDir),
130       rules(rval.rules),
131       logFile(rval.logFile),
132       pidFile(rval.pidFile),
133       monitorDir(rval.monitorDir),
134       monitoring(rval.monitoring),
135       detailStatWritePeriod(rval.detailStatWritePeriod),
136       statWritePeriod(rval.statWritePeriod),
137       stgExecMsgKey(rval.stgExecMsgKey),
138       executersNum(rval.executersNum),
139       fullFee(rval.fullFee),
140       dayFee(rval.dayFee),
141       dayResetTraff(rval.dayResetTraff),
142       spreadFee(rval.spreadFee),
143       freeMbAllowInet(rval.freeMbAllowInet),
144       dayFeeIsLastDay(rval.dayFeeIsLastDay),
145       stopOnError(rval.stopOnError),
146       writeFreeMbTraffCost(rval.writeFreeMbTraffCost),
147       showFeeInCash(rval.showFeeInCash),
148       messageTimeout(rval.messageTimeout),
149       feeChargeType(rval.feeChargeType),
150       reconnectOnTariffChange(rval.reconnectOnTariffChange),
151       disableSessionLog(rval.disableSessionLog),
152       filterParamsLog(rval.filterParamsLog),
153       modulesSettings(rval.modulesSettings),
154       storeModuleSettings(rval.storeModuleSettings),
155       logger(GetStgLogger())
156 {
157 }
158 //-----------------------------------------------------------------------------
159 SETTINGS_IMPL & SETTINGS_IMPL::operator=(const SETTINGS_IMPL & rhs)
160 {
161     modulesPath = rhs.modulesPath;
162     dirName = rhs.dirName;
163     confDir = rhs.confDir;
164     scriptsDir = rhs.scriptsDir;
165     rules = rhs.rules;
166     logFile = rhs.logFile;
167     pidFile = rhs.pidFile;
168     monitorDir = rhs.monitorDir;
169     scriptParams = rhs.scriptParams;
170     monitoring = rhs.monitoring;
171     detailStatWritePeriod = rhs.detailStatWritePeriod;
172     statWritePeriod = rhs.statWritePeriod;
173     stgExecMsgKey = rhs.stgExecMsgKey;
174     executersNum = rhs.executersNum;
175     fullFee = rhs.fullFee;
176     dayFee = rhs.dayFee;
177     dayResetTraff = rhs.dayResetTraff;
178     spreadFee = rhs.spreadFee;
179     freeMbAllowInet = rhs.freeMbAllowInet;
180     dayFeeIsLastDay = rhs.dayFeeIsLastDay;
181     stopOnError = rhs.stopOnError;
182     writeFreeMbTraffCost = rhs.writeFreeMbTraffCost;
183     showFeeInCash = rhs.showFeeInCash;
184     messageTimeout = rhs.messageTimeout;
185     feeChargeType = rhs.feeChargeType;
186     reconnectOnTariffChange = rhs.reconnectOnTariffChange;
187     disableSessionLog = rhs.disableSessionLog;
188     filterParamsLog = rhs.filterParamsLog;
189
190     modulesSettings = rhs.modulesSettings;
191     storeModuleSettings = rhs.storeModuleSettings;
192     return *this;
193 }
194 //-----------------------------------------------------------------------------
195 void SETTINGS_IMPL::ErrorCallback(void * data, const char * buf)
196 {
197     printfd(__FILE__, "SETTINGS_IMPL::ErrorCallback() - %s\n", buf);
198     SETTINGS_IMPL * settings = static_cast<SETTINGS_IMPL *>(data);
199     settings->logger("%s", buf);
200 }
201 //-----------------------------------------------------------------------------
202 int SETTINGS_IMPL::ReadSettings()
203 {
204 const char * requiredOptions[] = {
205     "ModulesPath",
206     "Modules",
207     "StoreModule",
208     "Rules",
209     "LogFile",
210     "DetailStatWritePeriod",
211     "DayFee",
212     "DayResetTraff",
213     "SpreadFee",
214     "FreeMbAllowInet",
215     "DayFeeIsLastDay",
216     "WriteFreeMbTraffCost",
217     NULL
218     };
219 int storeModulesCount = 0;
220 modulesSettings.clear();
221
222 DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
223 conf.setErrorCallback(SETTINGS_IMPL::ErrorCallback, this);
224 conf.setRequiredOptionNames(requiredOptions);
225 std::string confFile = confDir + "/stargazer.conf";
226
227 if(conf.setContent(confFile.c_str()) != 0)
228     {
229     strError = "Cannot read file " + confFile;
230     return -1;
231     }
232
233 const DOTCONFDocumentNode * node = conf.getFirstNode();
234
235 while (node)
236     {
237     if (strcasecmp(node->getName(), "ScriptDir") == 0)
238         {
239         scriptsDir = node->getValue(0);
240         }
241
242     if (strcasecmp(node->getName(), "LogFile") == 0)
243         {
244         logFile = node->getValue(0);
245         }
246
247     if (strcasecmp(node->getName(), "PIDFile") == 0)
248         {
249         pidFile = node->getValue(0);
250         }
251
252     if (strcasecmp(node->getName(), "ModulesPath") == 0)
253         {
254         modulesPath = node->getValue(0);
255         }
256
257     if (strcasecmp(node->getName(), "Rules") == 0)
258         {
259         rules = node->getValue(0);
260         }
261
262     if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
263         {
264         try
265         {
266             detailStatWritePeriod = toPeriod(node->getValue(0));
267         }
268         catch (const Error& error)
269         {
270             strError = error.what();
271             return -1;
272         }
273         }
274
275     if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
276         {
277         if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
278             {
279             strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
280             return -1;
281             }
282         }
283
284     if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
285         {
286         if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
287             {
288             strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
289             return -1;
290             }
291         }
292
293     if (strcasecmp(node->getName(), "ExecutersNum") == 0)
294         {
295         if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
296             {
297             strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
298             return -1;
299             }
300         }
301
302     if (strcasecmp(node->getName(), "DayFee") == 0)
303         {
304         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
305             {
306             strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
307             return -1;
308             }
309         }
310
311     if (strcasecmp(node->getName(), "FullFee") == 0)
312         {
313         if (ParseYesNo(node->getValue(0), &fullFee) != 0)
314             {
315             strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
316             return -1;
317             }
318         }
319
320     if (strcasecmp(node->getName(), "DayResetTraff") == 0)
321         {
322         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
323             {
324             strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
325             return -1;
326             }
327         }
328
329     if (strcasecmp(node->getName(), "SpreadFee") == 0)
330         {
331         if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
332             {
333             strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
334             return -1;
335             }
336         }
337
338     if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
339         {
340         if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
341             {
342             strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
343             return -1;
344             }
345         }
346
347     if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
348         {
349         if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
350             {
351             strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
352             return -1;
353             }
354         }
355
356     if (strcasecmp(node->getName(), "StopOnError") == 0)
357         {
358         if (ParseYesNo(node->getValue(0), &stopOnError) != 0)
359             {
360             strError = "Incorrect StopOnError value: \'" + std::string(node->getValue(0)) + "\'";
361             return -1;
362             }
363         }
364
365     if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
366         {
367         if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
368             {
369             strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
370             return -1;
371             }
372         }
373
374     if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
375         {
376         if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
377             {
378             strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
379             return -1;
380             }
381         }
382
383     if (strcasecmp(node->getName(), "MonitorDir") == 0)
384         {
385         monitorDir = node->getValue(0);
386         struct stat stat;
387         monitoring = false;
388
389         if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
390             {
391             monitoring = true;
392             }
393         }
394
395     if (strcasecmp(node->getName(), "MessageTimeout") == 0)
396         {
397         if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
398             {
399             strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
400             return -1;
401             }
402         }
403
404     if (strcasecmp(node->getName(), "FeeChargeType") == 0)
405         {
406         if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
407             {
408             strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
409             return -1;
410             }
411         }
412
413     if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
414         {
415         if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
416             {
417             strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
418             return -1;
419             }
420         }
421
422     if (strcasecmp(node->getName(), "DisableSessionLog") == 0)
423         {
424         if (ParseYesNo(node->getValue(0), &disableSessionLog) != 0)
425             {
426             strError = "Incorrect DisableSessionLog value: \'" + std::string(node->getValue(0)) + "\'";
427             return -1;
428             }
429         }
430
431     if (strcasecmp(node->getName(), "FilterParamsLog") == 0)
432         {
433         filterParamsLog.clear();
434         for (int i = 0; node->getValue(i) != NULL; ++i)
435             filterParamsLog.push_back(node->getValue(i));
436         }
437
438     if (strcasecmp(node->getName(), "DirNames") == 0)
439         {
440         const DOTCONFDocumentNode * child = node->getChildNode();
441         if (child)
442             {
443             const DOTCONFDocumentNode * dirNameNode;
444             dirName.reserve(DIR_NUM);
445             for (int i = 0; i < DIR_NUM; i++)
446                 {
447                 char strDirName[12];
448                 sprintf(strDirName, "DirName%d", i);
449                 dirNameNode = conf.findNode(strDirName, node);
450                 if (dirNameNode && dirNameNode->getValue(0))
451                     {
452                     dirName[i] = dirNameNode->getValue(0);
453                     }
454                 }
455             }
456         }
457
458     if (strcasecmp(node->getName(), "StoreModule") == 0)
459         {
460         if (node->getValue(1))
461             {
462             strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
463             return -1;
464             }
465
466         if (storeModulesCount)
467             {
468             strError = "Should be only one StoreModule.";
469             return -1;
470             }
471         storeModulesCount++;
472
473         if (node->getValue(0) == NULL)
474             {
475             strError = "No module name in the StoreModule section.";
476             return -1;
477             }
478         storeModuleSettings.moduleName = node->getValue(0);
479         storeModuleSettings.moduleParams = toPVS(*node);
480         }
481
482     if (strcasecmp(node->getName(), "Modules") == 0)
483         {
484         if (node->getValue(0))
485             {
486             strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
487             return -1;
488             }
489         const DOTCONFDocumentNode * child = node->getChildNode();
490         while (child)
491             {
492             if (strcasecmp(child->getName(), "Module") != 0)
493                 {
494                 child = child->getNextNode();
495                 continue;
496                 }
497
498             if (child->getValue(0) == NULL)
499                 {
500                 strError = "No module name in the Module section.";
501                 return -1;
502                 }
503
504             modulesSettings.push_back(MODULE_SETTINGS(child->getValue(0), toPVS(*child)));
505
506             child = child->getNextNode();
507             }
508         }
509
510     if (strcasecmp(node->getName(), "ScriptParams") == 0)
511         {
512         for (int i = 0; node->getValue(i) != NULL; ++i)
513             scriptParams.push_back(node->getValue(i));
514         }
515     node = node->getNextNode();
516     }
517
518 return 0;
519 }
520 //-----------------------------------------------------------------------------