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