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