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