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