]> git.stg.codes - stg.git/blob - projects/stargazer/settings_impl.cpp
Merge branch 'stg-2.409' into 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       writeFreeMbTraffCost(false),
114       showFeeInCash(true),
115       messageTimeout(0),
116       feeChargeType(0),
117       reconnectOnTariffChange(false),
118       logger(GetStgLogger())
119 {
120 }
121 //-----------------------------------------------------------------------------
122 SETTINGS_IMPL::SETTINGS_IMPL(const SETTINGS_IMPL & rval)
123     : SETTINGS(),
124       strError(),
125       modulesPath(rval.modulesPath),
126       dirName(rval.dirName),
127       confDir(rval.confDir),
128       scriptsDir(rval.scriptsDir),
129       rules(rval.rules),
130       logFile(rval.logFile),
131       pidFile(rval.pidFile),
132       monitorDir(rval.monitorDir),
133       monitoring(rval.monitoring),
134       detailStatWritePeriod(rval.detailStatWritePeriod),
135       statWritePeriod(rval.statWritePeriod),
136       stgExecMsgKey(rval.stgExecMsgKey),
137       executersNum(rval.executersNum),
138       fullFee(rval.fullFee),
139       dayFee(rval.dayFee),
140       dayResetTraff(rval.dayResetTraff),
141       spreadFee(rval.spreadFee),
142       freeMbAllowInet(rval.freeMbAllowInet),
143       dayFeeIsLastDay(rval.dayFeeIsLastDay),
144       writeFreeMbTraffCost(rval.writeFreeMbTraffCost),
145       showFeeInCash(rval.showFeeInCash),
146       messageTimeout(rval.messageTimeout),
147       feeChargeType(rval.feeChargeType),
148       reconnectOnTariffChange(rval.reconnectOnTariffChange),
149       modulesSettings(rval.modulesSettings),
150       storeModuleSettings(rval.storeModuleSettings),
151       logger(GetStgLogger())
152 {
153 }
154 //-----------------------------------------------------------------------------
155 SETTINGS_IMPL & SETTINGS_IMPL::operator=(const SETTINGS_IMPL & rhs)
156 {
157     modulesPath = rhs.modulesPath;
158     dirName = rhs.dirName;
159     confDir = rhs.confDir;
160     scriptsDir = rhs.scriptsDir;
161     rules = rhs.rules;
162     logFile = rhs.logFile;
163     pidFile = rhs.pidFile;
164     monitorDir = rhs.monitorDir;
165     scriptParams = rhs.scriptParams;
166     monitoring = rhs.monitoring;
167     detailStatWritePeriod = rhs.detailStatWritePeriod;
168     statWritePeriod = rhs.statWritePeriod;
169     stgExecMsgKey = rhs.stgExecMsgKey;
170     executersNum = rhs.executersNum;
171     fullFee = rhs.fullFee;
172     dayFee = rhs.dayFee;
173     dayResetTraff = rhs.dayResetTraff;
174     spreadFee = rhs.spreadFee;
175     freeMbAllowInet = rhs.freeMbAllowInet;
176     dayFeeIsLastDay = rhs.dayFeeIsLastDay;
177     writeFreeMbTraffCost = rhs.writeFreeMbTraffCost;
178     showFeeInCash = rhs.showFeeInCash;
179     messageTimeout = rhs.messageTimeout;
180     feeChargeType = rhs.feeChargeType;
181     reconnectOnTariffChange = rhs.reconnectOnTariffChange;
182
183     modulesSettings = rhs.modulesSettings;
184     storeModuleSettings = rhs.storeModuleSettings;
185     return *this;
186 }
187 //-----------------------------------------------------------------------------
188 int SETTINGS_IMPL::ParseModuleSettings(const DOTCONFDocumentNode * node, std::vector<PARAM_VALUE> * params)
189 {
190 const DOTCONFDocumentNode * childNode;
191 PARAM_VALUE pv;
192 const char * value;
193
194 pv.param = node->getName();
195
196 if (node->getValue(1))
197     {
198     strError = "Unexpected value \'" + std::string(node->getValue(1)) + "\'.";
199     return -1;
200     }
201
202 value = node->getValue(0);
203
204 if (!value)
205     {
206     strError = "Module name expected.";
207     return -1;
208     }
209
210 childNode = node->getChildNode();
211 while (childNode)
212     {
213     pv.param = childNode->getName();
214     int i = 0;
215     while ((value = childNode->getValue(i++)) != NULL)
216         {
217         pv.value.push_back(value);
218         }
219     params->push_back(pv);
220     pv.value.clear();
221     childNode = childNode->getNextNode();
222     }
223
224 return 0;
225 }
226 //-----------------------------------------------------------------------------
227 void SETTINGS_IMPL::ErrorCallback(void * data, const char * buf)
228 {
229     printfd(__FILE__, "SETTINGS_IMPL::ErrorCallback() - %s\n", buf);
230     SETTINGS_IMPL * settings = static_cast<SETTINGS_IMPL *>(data);
231     settings->logger("%s", buf);
232 }
233 //-----------------------------------------------------------------------------
234 int SETTINGS_IMPL::ReadSettings()
235 {
236 const char * requiredOptions[] = {
237     "ModulesPath",
238     "Modules",
239     "StoreModule",
240     "Rules",
241     "LogFile",
242     "DetailStatWritePeriod",
243     "DayFee",
244     "DayResetTraff",
245     "SpreadFee",
246     "FreeMbAllowInet",
247     "DayFeeIsLastDay",
248     "WriteFreeMbTraffCost",
249     NULL
250     };
251 int storeModulesCount = 0;
252 modulesSettings.clear();
253
254 DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
255 conf.setErrorCallback(SETTINGS_IMPL::ErrorCallback, this);
256 conf.setRequiredOptionNames(requiredOptions);
257 std::string confFile = confDir + "/stargazer.conf";
258
259 if(conf.setContent(confFile.c_str()) != 0)
260     {
261     strError = "Cannot read file " + confFile;
262     return -1;
263     }
264
265 const DOTCONFDocumentNode * node = conf.getFirstNode();
266
267 while (node)
268     {
269     if (strcasecmp(node->getName(), "ScriptDir") == 0)
270         {
271         scriptsDir = node->getValue(0);
272         }
273
274     if (strcasecmp(node->getName(), "LogFile") == 0)
275         {
276         logFile = node->getValue(0);
277         }
278
279     if (strcasecmp(node->getName(), "PIDFile") == 0)
280         {
281         pidFile = node->getValue(0);
282         }
283
284     if (strcasecmp(node->getName(), "ModulesPath") == 0)
285         {
286         modulesPath = node->getValue(0);
287         }
288
289     if (strcasecmp(node->getName(), "Rules") == 0)
290         {
291         rules = node->getValue(0);
292         }
293
294     if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
295         {
296         try
297         {
298             detailStatWritePeriod = toPeriod(node->getValue(0));
299         }
300         catch (const Error& error)
301         {
302             strError = error.what();
303             return -1;
304         }
305         }
306
307     if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
308         {
309         if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
310             {
311             strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
312             return -1;
313             }
314         }
315
316     if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
317         {
318         if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
319             {
320             strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
321             return -1;
322             }
323         }
324
325     if (strcasecmp(node->getName(), "ExecutersNum") == 0)
326         {
327         if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
328             {
329             strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
330             return -1;
331             }
332         }
333
334     if (strcasecmp(node->getName(), "DayFee") == 0)
335         {
336         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
337             {
338             strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
339             return -1;
340             }
341         }
342
343     if (strcasecmp(node->getName(), "FullFee") == 0)
344         {
345         if (ParseYesNo(node->getValue(0), &fullFee) != 0)
346             {
347             strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
348             return -1;
349             }
350         }
351
352     if (strcasecmp(node->getName(), "DayResetTraff") == 0)
353         {
354         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
355             {
356             strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
357             return -1;
358             }
359         }
360
361     if (strcasecmp(node->getName(), "SpreadFee") == 0)
362         {
363         if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
364             {
365             strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
366             return -1;
367             }
368         }
369
370     if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
371         {
372         if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
373             {
374             strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
375             return -1;
376             }
377         }
378
379     if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
380         {
381         if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
382             {
383             strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
384             return -1;
385             }
386         }
387
388     if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
389         {
390         if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
391             {
392             strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
393             return -1;
394             }
395         }
396
397     if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
398         {
399         if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
400             {
401             strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
402             return -1;
403             }
404         }
405
406     if (strcasecmp(node->getName(), "MonitorDir") == 0)
407         {
408         monitorDir = node->getValue(0);
409         struct stat stat;
410         monitoring = false;
411
412         if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
413             {
414             monitoring = true;
415             }
416         }
417
418     if (strcasecmp(node->getName(), "MessageTimeout") == 0)
419         {
420         if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
421             {
422             strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
423             return -1;
424             }
425         }
426
427     if (strcasecmp(node->getName(), "FeeChargeType") == 0)
428         {
429         if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
430             {
431             strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
432             return -1;
433             }
434         }
435
436     if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
437         {
438         if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
439             {
440             strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
441             return -1;
442             }
443         }
444
445     if (strcasecmp(node->getName(), "DirNames") == 0)
446         {
447         const DOTCONFDocumentNode * child = node->getChildNode();
448         if (child)
449             {
450             const DOTCONFDocumentNode * dirNameNode;
451             dirName.reserve(DIR_NUM);
452             for (int i = 0; i < DIR_NUM; i++)
453                 {
454                 char strDirName[12];
455                 sprintf(strDirName, "DirName%d", i);
456                 dirNameNode = conf.findNode(strDirName, node);
457                 if (dirNameNode && dirNameNode->getValue(0))
458                     {
459                     dirName[i] = dirNameNode->getValue(0);
460                     }
461                 }
462             }
463         }
464
465     if (strcasecmp(node->getName(), "StoreModule") == 0)
466         {
467         if (node->getValue(1))
468             {
469             strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
470             return -1;
471             }
472
473         if (storeModulesCount)
474             {
475             strError = "Should be only one StoreModule.";
476             return -1;
477             }
478         storeModulesCount++;
479
480         if (node->getValue(0) == NULL)
481             {
482             strError = "No module name in the StoreModule section.";
483             return -1;
484             }
485         storeModuleSettings.moduleName = node->getValue(0);
486         storeModuleSettings.moduleParams = toPVS(*node);
487         }
488
489     if (strcasecmp(node->getName(), "Modules") == 0)
490         {
491         if (node->getValue(0))
492             {
493             strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
494             return -1;
495             }
496         const DOTCONFDocumentNode * child = node->getChildNode();
497         while (child)
498             {
499             if (strcasecmp(child->getName(), "Module") != 0)
500                 {
501                 child = child->getNextNode();
502                 continue;
503                 }
504
505             if (child->getValue(0) == NULL)
506                 {
507                 strError = "No module name in the Module section.";
508                 return -1;
509                 }
510
511             modulesSettings.push_back(MODULE_SETTINGS(child->getValue(0), toPVS(*child)));
512
513             child = child->getNextNode();
514             }
515         }
516
517     if (strcasecmp(node->getName(), "ScriptParams") == 0)
518         {
519         for (int i = 0; node->getValue(i) != NULL; ++i)
520             {
521             scriptParams.push_back(node->getValue(i));
522             }
523         }
524     node = node->getNextNode();
525     }
526
527 return 0;
528 }
529 //-----------------------------------------------------------------------------