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