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