]> git.stg.codes - stg.git/blob - projects/stargazer/main.cpp
Add explicit casts for reconnect-on-tariff-change tests to shut up gcc
[stg.git] / projects / stargazer / main.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  /*
22  $Revision: 1.124 $
23  $Date: 2010/10/04 20:19:12 $
24  $Author: faust $
25  */
26
27 #include <unistd.h>
28 #include <sys/ipc.h>
29 #include <sys/msg.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/stat.h> // S_IRUSR
33 #include <fcntl.h> // create
34
35 #include <csignal>
36 #include <cerrno>
37 #include <cstdio>
38 #include <cstdlib> // srandom, exit
39 #include <fstream>
40 #include <vector>
41 #include <set>
42 #include <list>
43
44 #include "stg/user.h"
45 #include "stg/common.h"
46 #include "stg/plugin.h"
47 #include "stg/logger.h"
48 #include "stg/scriptexecuter.h"
49 #include "stg/conffiles.h"
50 #include "stg/version.h"
51 #include "stg/pinger.h"
52 #include "stg_timer.h"
53 #include "settings_impl.h"
54 #include "users_impl.h"
55 #include "admins_impl.h"
56 #include "tariffs_impl.h"
57 #include "services_impl.h"
58 #include "corps_impl.h"
59 #include "traffcounter_impl.h"
60 #include "plugin_runner.h"
61 #include "store_loader.h"
62 #include "pidfile.h"
63 #include "eventloop.h"
64
65 using namespace std;
66
67 #ifdef DEBUG
68     #define MAIN_DEBUG (1)
69     #define NO_DAEMON  (1)
70 #endif
71
72 #define START_FILE "/._ST_ART_ED_"
73
74 set<pid_t> executersPid;
75
76 //-----------------------------------------------------------------------------
77 bool StartModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
78 {
79 return lhs.GetStartPosition() < rhs.GetStartPosition();
80 }
81 //-----------------------------------------------------------------------------
82 bool StopModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
83 {
84 return lhs.GetStopPosition() > rhs.GetStopPosition();
85 }
86 //-----------------------------------------------------------------------------
87 static void StartTimer()
88 {
89 STG_LOGGER & WriteServLog = GetStgLogger();
90
91 if (RunStgTimer())
92     {
93     WriteServLog("Cannot start timer. Fatal.");
94     //printfd(__FILE__, "Cannot start timer. Fatal.\n");
95     exit(1);
96     }
97 else
98     {
99     WriteServLog("Timer thread started successfully.");
100     //printfd(__FILE__, "Timer thread started successfully.\n");
101     }
102 }
103 //-----------------------------------------------------------------------------
104 int StartScriptExecuter(char * procName, int msgKey, int * msgID, SETTINGS_IMPL * settings)
105 {
106 STG_LOGGER & WriteServLog = GetStgLogger();
107
108 if (*msgID == -11)   // If msgID == -11 - first call. Create queue
109     {
110     for (int i = 0; i < 2; i++)
111         {
112         *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
113
114         if (*msgID == -1)
115             {
116             *msgID = msgget(msgKey, 0);
117             if (*msgID == -1)
118                 {
119                 WriteServLog("Message queue not created.");
120                 return -1;
121                 }
122             else
123                 {
124                 msgctl(*msgID, IPC_RMID, NULL);
125                 }
126             }
127         else
128             {
129             WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
130             break;
131             }
132         }
133     }
134
135 pid_t executerPid = fork();
136
137 switch (executerPid)
138     {
139     case -1:
140         WriteServLog("Fork error!");
141         return -1;
142
143     case 0:
144         delete settings;
145         Executer(*msgID, executerPid, procName);
146         return 1;
147
148     default:
149         if (executersPid.empty()) {
150             Executer(*msgID, executerPid, NULL);
151         }
152         executersPid.insert(executerPid);
153     }
154 return 0;
155 }
156 //-----------------------------------------------------------------------------
157 #ifndef NO_DAEMON
158 int ForkAndWait(const string & confDir)
159 #else
160 int ForkAndWait(const string &)
161 #endif
162 {
163 #ifndef NO_DAEMON
164 stgChildPid = fork();
165 string startFile = confDir + START_FILE;
166 unlink(startFile.c_str());
167
168 switch (stgChildPid)
169     {
170     case -1:
171         return -1;
172         break;
173
174     case 0:
175         close(1);
176         close(2);
177         setsid();
178         break;
179
180     default:
181         struct timespec ts = {0, 200000000};
182         for (int i = 0; i < 120 * 5; i++)
183             {
184             if (access(startFile.c_str(), F_OK) == 0)
185                 {
186                 unlink(startFile.c_str());
187                 exit(0);
188                 }
189
190             nanosleep(&ts, NULL);
191             }
192         unlink(startFile.c_str());
193         exit(1);
194         break;
195     }
196 #endif
197 return 0;
198 }
199 //-----------------------------------------------------------------------------
200 void KillExecuters()
201 {
202 set<pid_t>::iterator pid;
203 pid = executersPid.begin();
204 while (pid != executersPid.end())
205     {
206     printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
207     kill(*pid, SIGUSR1);
208     ++pid;
209     }
210 }
211 //-----------------------------------------------------------------------------
212 int main(int argc, char * argv[])
213 {
214 SETTINGS_IMPL * settings = NULL;
215 STORE * dataStore = NULL;
216 TARIFFS_IMPL * tariffs = NULL;
217 ADMINS_IMPL * admins = NULL;
218 USERS_IMPL * users = NULL;
219 TRAFFCOUNTER_IMPL * traffCnt = NULL;
220 SERVICES_IMPL * services = NULL;
221 CORPORATIONS_IMPL * corps = NULL;
222 int msgID = -11;
223
224     {
225     STG_LOGGER & WriteServLog = GetStgLogger();
226     WriteServLog.SetLogFileName("/var/log/stargazer.log");
227     }
228
229 vector<MODULE_SETTINGS> modSettings;
230 list<PLUGIN_RUNNER> modules;
231
232 list<PLUGIN_RUNNER>::iterator modIter;
233
234 if (getuid())
235     {
236     printf("You must be root. Exit.\n");
237     exit(1);
238     }
239
240 if (argc == 2)
241     settings = new SETTINGS_IMPL(argv[1]);
242 else
243     settings = new SETTINGS_IMPL();
244
245 if (settings->ReadSettings())
246     {
247     STG_LOGGER & WriteServLog = GetStgLogger();
248
249     if (settings->GetLogFileName() != "")
250         WriteServLog.SetLogFileName(settings->GetLogFileName());
251
252     WriteServLog("ReadSettings error. %s", settings->GetStrError().c_str());
253     exit(1);
254     }
255
256 #ifndef NO_DAEMON
257 string startFile(settings->GetConfDir() + START_FILE);
258 #endif
259
260 if (ForkAndWait(settings->GetConfDir()) < 0)
261     {
262     STG_LOGGER & WriteServLog = GetStgLogger();
263     WriteServLog("Fork error!");
264     exit(1);
265     }
266
267 STG_LOGGER & WriteServLog = GetStgLogger();
268 WriteServLog.SetLogFileName(settings->GetLogFileName());
269 WriteServLog("Stg v. %s", SERVER_VERSION);
270
271 for (size_t i = 0; i < settings->GetExecutersNum(); i++)
272     {
273     int ret = StartScriptExecuter(argv[0], settings->GetExecMsgKey(), &msgID, settings);
274     if (ret < 0)
275         {
276         STG_LOGGER & WriteServLog = GetStgLogger();
277         WriteServLog("Start Script Executer error!");
278         return 1;
279         }
280     if (ret == 1)
281         {
282         // Stopping child
283         return 0;
284         }
285     }
286
287 PIDFile pidFile(settings->GetPIDFileName());
288
289 sigset_t signalSet;
290 sigfillset(&signalSet);
291 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
292
293 StartTimer();
294 WaitTimer();
295 if (!IsStgTimerRunning())
296     {
297     printfd(__FILE__, "Timer thread not started in 1 sec!\n");
298     WriteServLog("Timer thread not started in 1 sec!");
299     }
300
301 EVENT_LOOP & loop(EVENT_LOOP_SINGLETON::GetInstance());
302
303 STORE_LOADER storeLoader(*settings);
304 if (storeLoader.Load())
305     {
306     WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
307     goto exitLblNotStarted;
308     }
309
310 if (loop.Start())
311     {
312     WriteServLog("Event loop not started.");
313     goto exitLblNotStarted;
314     }
315
316 dataStore = storeLoader.GetStore();
317 WriteServLog("Storage plugin: %s. Loading successfull.", dataStore->GetVersion().c_str());
318
319 tariffs = new TARIFFS_IMPL(dataStore);
320 admins = new ADMINS_IMPL(dataStore);
321 users = new USERS_IMPL(settings, dataStore, tariffs, admins->GetSysAdmin());
322 traffCnt = new TRAFFCOUNTER_IMPL(users, settings->GetRulesFileName());
323 services = new SERVICES_IMPL(dataStore);
324 corps = new CORPORATIONS_IMPL(dataStore);
325 traffCnt->SetMonitorDir(settings->GetMonitorDir());
326
327 modSettings = settings->GetModulesSettings();
328
329 for (size_t i = 0; i < modSettings.size(); i++)
330     {
331     string modulePath = settings->GetModulesPath();
332     modulePath += "/mod_";
333     modulePath += modSettings[i].moduleName;
334     modulePath += ".so";
335     printfd(__FILE__, "Module: %s\n", modulePath.c_str());
336     modules.push_back(
337         PLUGIN_RUNNER(modulePath,
338                       modSettings[i],
339                       admins,
340                       tariffs,
341                       users,
342                       services,
343                       corps,
344                       traffCnt,
345                       dataStore,
346                       settings)
347         );
348     }
349
350 modIter = modules.begin();
351
352 while (modIter != modules.end())
353     {
354     if (modIter->Load())
355         {
356         WriteServLog("Error: %s",
357                      modIter->GetStrError().c_str());
358         goto exitLblNotStarted;
359         }
360     ++modIter;
361     }
362
363 if (users->Start())
364     {
365     goto exitLblNotStarted;
366     }
367 WriteServLog("Users started successfully.");
368
369 if (traffCnt->Start())
370     {
371     goto exitLblNotStarted;
372     }
373 WriteServLog("Traffcounter started successfully.");
374
375 //Sort by start order
376 modules.sort(StartModCmp);
377 modIter = modules.begin();
378
379 while (modIter != modules.end())
380     {
381     if (modIter->Start())
382         {
383         WriteServLog("Error: %s",
384                      modIter->GetStrError().c_str());
385         goto exitLbl;
386         }
387     WriteServLog("Module: '%s'. Start successfull.", modIter->GetPlugin()->GetVersion().c_str());
388     ++modIter;
389     }
390
391 srandom(stgTime);
392
393 WriteServLog("Stg started successfully.");
394 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
395
396 #ifndef NO_DAEMON
397 creat(startFile.c_str(), S_IRUSR);
398 #endif
399
400 while (true)
401     {
402     sigfillset(&signalSet);
403     int sig = 0;
404     sigwait(&signalSet, &sig);
405     bool stop = false;
406     int status;
407     pid_t childPid;
408     set<pid_t>::iterator it;
409     switch (sig)
410         {
411         case SIGHUP:
412             traffCnt->Reload();
413             modIter = modules.begin();
414             for (; modIter != modules.end(); ++modIter)
415                 {
416                 if (modIter->Reload())
417                     {
418                     WriteServLog("Error reloading %s ('%s')", modIter->GetPlugin()->GetVersion().c_str(),
419                                                               modIter->GetStrError().c_str());
420                     printfd(__FILE__, "Error reloading %s ('%s')\n", modIter->GetPlugin()->GetVersion().c_str(),
421                                                                      modIter->GetStrError().c_str());
422                     }
423                 }
424             break;
425         case SIGTERM:
426             stop = true;
427             break;
428         case SIGINT:
429             stop = true;
430             break;
431         case SIGPIPE:
432             WriteServLog("Broken pipe!");
433             break;
434         case SIGCHLD:
435             childPid = waitpid(-1, &status, WNOHANG);
436
437             it = executersPid.find(childPid);
438             if (it != executersPid.end())
439                 {
440                 executersPid.erase(it);
441                 if (executersPid.empty())
442                     stop = true;
443                 }
444             break;
445         default:
446             WriteServLog("Ignore signel %d", sig);
447             break;
448         }
449     if (stop)
450         break;
451     }
452
453 exitLbl:
454
455 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
456
457 //Sort by start order
458 modules.sort(StopModCmp);
459 modIter = modules.begin();
460 while (modIter != modules.end())
461     {
462     std::string name = modIter->GetFileName();
463     printfd(__FILE__, "Stopping module '%s'\n", name.c_str());
464     if (modIter->Stop())
465         {
466         WriteServLog("Module \'%s\': Error: %s",
467                      modIter->GetPlugin()->GetVersion().c_str(),
468                      modIter->GetStrError().c_str());
469         printfd(__FILE__, "Failed to stop module '%s'\n", name.c_str());
470         }
471     WriteServLog("Module: \'%s\'. Stop successfull.", modIter->GetPlugin()->GetVersion().c_str());
472     ++modIter;
473     }
474
475 if (loop.Stop())
476     {
477     WriteServLog("Event loop not stopped.");
478     }
479
480 exitLblNotStarted:
481
482 modIter = modules.begin();
483 while (modIter != modules.end())
484     {
485     std::string name = modIter->GetFileName();
486     if (modIter->IsRunning())
487         {
488         printfd(__FILE__, "Passing module '%s' `cause it's still running\n", name.c_str());
489         }
490     else
491         {
492         printfd(__FILE__, "Unloading module '%s'\n", name.c_str());
493         if (modIter->Unload())
494             {
495             WriteServLog("Module \'%s\': Error: %s",
496                          name.c_str(),
497                          modIter->GetStrError().c_str());
498             printfd(__FILE__, "Failed to unload module '%s'\n", name.c_str());
499             }
500         }
501     ++modIter;
502     }
503
504 if (traffCnt)
505     {
506     traffCnt->Stop();
507     WriteServLog("Traffcounter: Stop successfull.");
508     }
509
510 if (users)
511     {
512     users->Stop();
513     WriteServLog("Users: Stop successfull.");
514     }
515
516 sleep(1);
517 int res = msgctl(msgID, IPC_RMID, NULL);
518 if (res)
519     WriteServLog("Queue was not removed. id=%d", msgID);
520 else
521     WriteServLog("Queue removed successfully.");
522
523 KillExecuters();
524
525 StopStgTimer();
526 WriteServLog("StgTimer: Stop successfull.");
527
528 delete corps;
529 delete services;
530 delete traffCnt;
531 delete users;
532 delete admins;
533 delete tariffs;
534 delete settings;
535
536 WriteServLog("Stg stopped successfully.");
537 WriteServLog("---------------------------------------------");
538
539 return 0;
540 }
541 //-----------------------------------------------------------------------------