]> git.stg.codes - stg.git/blob - projects/stargazer/main.cpp
Add sys/types.h for FreeBSD
[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
33 #include <csignal>
34 #include <cerrno>
35 #include <cstdio>
36 #include <fstream>
37 #include <vector>
38 #include <set>
39 #include <list>
40
41 #include "settings_impl.h"
42 #include "user.h"
43 #include "users_impl.h"
44 #include "admins_impl.h"
45 #include "tariffs_impl.h"
46 #include "common.h"
47 #include "traffcounter_impl.h"
48 #include "plugin.h"
49 #include "stg_logger.h"
50 #include "stg_timer.h"
51 #include "plugin_runner.h"
52 #include "script_executer.h"
53 #include "conffiles.h"
54 #include "version.h"
55 #include "store_loader.h"
56 #include "pidfile.h"
57 #include "eventloop.h"
58
59 using namespace std;
60 uint32_t        eip;
61
62 #ifdef DEBUG
63     #define MAIN_DEBUG (1)
64     #define NO_DAEMON  (1)
65 #endif
66
67 #define START_FILE "/._ST_ART_ED_"
68
69 static bool needRulesReloading = false;
70 static bool childExited = false;
71 //static pid_t executerPid;
72 set<pid_t> executersPid;
73 static pid_t stgChildPid;
74
75 #include "pinger.h"
76
77 //-----------------------------------------------------------------------------
78 bool StartModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
79 {
80 return lhs.GetStartPosition() < rhs.GetStartPosition();
81 }
82 //-----------------------------------------------------------------------------
83 bool StopModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
84 {
85 return lhs.GetStopPosition() > rhs.GetStopPosition();
86 }
87 //-----------------------------------------------------------------------------
88 class STG_STOPPER
89 {
90 public:
91     STG_STOPPER() { nonstop = true; }
92     bool    GetStatus() const { return nonstop; };
93     #ifdef NO_DAEMON
94     void    Stop(const char * __file__, int __line__)
95     #else
96     void    Stop(const char *, int)
97     #endif
98         {
99         #ifdef NO_DAEMON
100         printfd(__FILE__, "Stg stopped at %s:%d\n", __file__, __line__);
101         #endif
102         nonstop = false;
103         }
104 private:
105     bool nonstop;
106 };
107 //-----------------------------------------------------------------------------
108 STG_STOPPER nonstop;
109 //-----------------------------------------------------------------------------
110 static void StartTimer()
111 {
112 STG_LOGGER & WriteServLog = GetStgLogger();
113
114 if (RunStgTimer())
115     {
116     WriteServLog("Cannot start timer. Fatal.");
117     //printfd(__FILE__, "Cannot start timer. Fatal.\n");
118     exit(1);
119     }
120 else
121     {
122     WriteServLog("Timer thread started successfully.");
123     //printfd(__FILE__, "Timer thread started successfully.\n");
124     }
125 }
126 //-----------------------------------------------------------------------------
127 void CatchUSR1(int)
128 {
129
130 }
131 //-----------------------------------------------------------------------------
132 void CatchTERM(int sig)
133 {
134 /*
135  *Function Name:CatchINT
136  *Parameters: sig_num - ÎÏÍÅÒ ÓÉÇÎÁÌÁ
137  *Description: ïÂÒÁÂÏÔÞÉË ÓÉÇÎÁÌÁ INT
138  *Returns: îÉÞÅÇÏ
139  */
140 STG_LOGGER & WriteServLog = GetStgLogger();
141 WriteServLog("Shutting down... %d", sig);
142
143 //nonstop = false;
144 nonstop.Stop(__FILE__, __LINE__);
145
146 struct sigaction newsa, oldsa;
147 sigset_t sigmask;
148
149 sigemptyset(&sigmask);
150 sigaddset(&sigmask, SIGTERM);
151 newsa.sa_handler = SIG_IGN;
152 newsa.sa_mask = sigmask;
153 newsa.sa_flags = 0;
154 sigaction(SIGTERM, &newsa, &oldsa);
155
156 sigemptyset(&sigmask);
157 sigaddset(&sigmask, SIGINT);
158 newsa.sa_handler = SIG_IGN;
159 newsa.sa_mask = sigmask;
160 newsa.sa_flags = 0;
161 sigaction(SIGINT, &newsa, &oldsa);
162 }
163 //-----------------------------------------------------------------------------
164 void CatchPIPE(int)
165 {
166 STG_LOGGER & WriteServLog = GetStgLogger();
167 WriteServLog("Broken pipe!");
168 }
169 //-----------------------------------------------------------------------------
170 void CatchHUP(int)
171 {
172 needRulesReloading = true;
173 }
174 //-----------------------------------------------------------------------------
175 void CatchCHLD(int)
176 {
177 int status;
178 pid_t childPid;
179 childPid = waitpid(-1, &status, WNOHANG);
180
181 set<pid_t>::iterator pid;
182 pid = executersPid.find(childPid);
183 if (pid != executersPid.end())
184     {
185     executersPid.erase(pid);
186     if (executersPid.empty() && nonstop.GetStatus())
187         {
188         nonstop.Stop(__FILE__, __LINE__);
189         }
190     }
191 if (childPid == stgChildPid)
192     {
193     childExited = true;
194     }
195 }
196 /*//-----------------------------------------------------------------------------
197 void CatchSEGV(int, siginfo_t *, void *)
198 {
199 char fileName[50];
200 sprintf(fileName, "/tmp/stg_segv.%d", getpid());
201 FILE * f = fopen(fileName, "wt");
202 if (f)
203     {
204     fprintf(f, "\nSignal info:\n~~~~~~~~~~~~\n");
205     fprintf(f, "numb:\t %d (%d)\n", sinfo->si_signo, sig);
206     fprintf(f, "errn:\t %d\n", sinfo->si_errno);
207     fprintf(f, "code:\t %d ", sinfo->si_code);
208
209     switch (sinfo->si_code)
210         {
211         case SEGV_MAPERR:
212             fprintf(f, "(SEGV_MAPERR - address not mapped to object)\n");
213             break;
214
215         case SEGV_ACCERR:
216             fprintf(f, "(SEGV_ACCERR - invalid permissions for mapped object)\n");
217             break;
218
219         default:
220             fprintf(f, "???\n");
221         }
222
223     fprintf(f, "addr:\t 0x%.8X\n",
224         (unsigned int)sinfo->si_addr);
225
226     Dl_info dlinfo;
227     //asm("movl %eip, eip");
228     if (dladdr((void*)CatchCHLD, &dlinfo))
229         {
230         fprintf(f, "SEGV point: %s %s\n", dlinfo.dli_fname, dlinfo.dli_sname);
231         }
232     else
233         {
234         fprintf(f, "Cannot find SEGV point\n");
235         }
236
237     fclose(f);
238     }
239
240 struct sigaction segv_action, segv_action_old;
241
242 segv_action.sa_handler = SIG_DFL;
243 segv_action.sa_sigaction = NULL;
244 segv_action.sa_flags = SA_SIGINFO;
245 segv_action.sa_restorer = NULL;
246
247 sigaction(SIGSEGV, &segv_action, &segv_action_old);
248 }*/
249 //-----------------------------------------------------------------------------
250 static void SetSignalHandlers()
251 {
252 struct sigaction newsa, oldsa;
253 sigset_t sigmask;
254 ///////
255 sigemptyset(&sigmask);
256 sigaddset(&sigmask, SIGTERM);
257 newsa.sa_handler = CatchTERM;
258 newsa.sa_mask = sigmask;
259 newsa.sa_flags = 0;
260 sigaction(SIGTERM, &newsa, &oldsa);
261 ///////
262 sigemptyset(&sigmask);
263 sigaddset(&sigmask, SIGUSR1);
264 newsa.sa_handler = CatchUSR1;
265 newsa.sa_mask = sigmask;
266 newsa.sa_flags = 0;
267 sigaction(SIGUSR1, &newsa, &oldsa);
268 ///////
269 sigemptyset(&sigmask);
270 sigaddset(&sigmask, SIGINT);
271 newsa.sa_handler = CatchTERM;
272 newsa.sa_mask = sigmask;
273 newsa.sa_flags = 0;
274 sigaction(SIGINT, &newsa, &oldsa);
275 //////
276 sigemptyset(&sigmask);
277 sigaddset(&sigmask, SIGPIPE);
278 newsa.sa_handler = CatchPIPE;
279 newsa.sa_mask = sigmask;
280 newsa.sa_flags = 0;
281 sigaction(SIGPIPE, &newsa, &oldsa);
282 //////
283 sigemptyset(&sigmask);
284 sigaddset(&sigmask, SIGHUP);
285 newsa.sa_handler = CatchHUP;
286 newsa.sa_mask = sigmask;
287 newsa.sa_flags = 0;
288 sigaction(SIGHUP, &newsa, &oldsa);
289 //////
290 sigemptyset(&sigmask);
291 sigaddset(&sigmask, SIGCHLD);
292 newsa.sa_handler = CatchCHLD;
293 newsa.sa_mask = sigmask;
294 newsa.sa_flags = 0;
295 sigaction(SIGCHLD, &newsa, &oldsa);
296
297 /*newsa.sa_handler = NULL;
298 newsa.sa_sigaction = CatchSEGV;
299 newsa.sa_flags = SA_SIGINFO;
300 newsa.sa_restorer = NULL;
301 sigaction(SIGSEGV, &newsa, &oldsa);*/
302
303 return;
304 }
305 //-----------------------------------------------------------------------------
306 int StartScriptExecuter(char * procName, int msgKey, int * msgID, SETTINGS_IMPL * settings)
307 {
308 STG_LOGGER & WriteServLog = GetStgLogger();
309
310 if (*msgID == -11)   // If msgID == -11 - first call. Create queue
311     {
312     for (int i = 0; i < 2; i++)
313         {
314         *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
315
316         if (*msgID == -1)
317             {
318             *msgID = msgget(msgKey, 0);
319             if (*msgID == -1)
320                 {
321                 WriteServLog("Message queue not created.");
322                 return -1;
323                 }
324             else
325                 {
326                 msgctl(*msgID, IPC_RMID, NULL);
327                 }
328             }
329         else
330             {
331             WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
332             break;
333             }
334         }
335     }
336
337 pid_t executerPid = fork();
338
339 switch (executerPid)
340     {
341     case -1:
342         WriteServLog("Fork error!");
343         return -1;
344
345     case 0:
346         delete settings;
347         Executer(msgKey, *msgID, executerPid, procName);
348         return 1;
349
350     default:
351         if (executersPid.empty()) {
352             Executer(msgKey, *msgID, executerPid, NULL);
353         }
354         executersPid.insert(executerPid);
355     }
356 return 0;
357 }
358 //-----------------------------------------------------------------------------
359 #ifndef NO_DAEMON
360 int ForkAndWait(const string & confDir)
361 #else
362 int ForkAndWait(const string &)
363 #endif
364 {
365 #ifndef NO_DAEMON
366 stgChildPid = fork();
367 string startFile = confDir + START_FILE;
368 unlink(startFile.c_str());
369
370 switch (stgChildPid)
371     {
372     case -1:
373         return -1;
374         break;
375
376     case 0:
377         close(1);
378         close(2);
379         setsid();
380         break;
381
382     default:
383         struct timespec ts = {0, 200000000};
384         for (int i = 0; i < 120 * 5; i++)
385             {
386             if (access(startFile.c_str(), F_OK) == 0)
387                 {
388                 unlink(startFile.c_str());
389                 exit(0);
390                 }
391
392             if (childExited)
393                 {
394                 unlink(startFile.c_str());
395                 exit(1);
396                 }
397             nanosleep(&ts, NULL);
398             }
399         unlink(startFile.c_str());
400         exit(1);
401         break;
402     }
403 #endif
404 return 0;
405 }
406 //-----------------------------------------------------------------------------
407 void KillExecuters()
408 {
409 set<pid_t>::iterator pid;
410 pid = executersPid.begin();
411 while (pid != executersPid.end())
412     {
413     printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
414     kill(*pid, SIGUSR1);
415     ++pid;
416     }
417 }
418 //-----------------------------------------------------------------------------
419 int main(int argc, char * argv[])
420 {
421
422 /*
423   Initialization order:
424   - Logger
425   - Stg timer
426   - Settings
427   - Plugins
428   - Plugins settings
429   - Read Admins
430   - Read Tariffs
431   - Read Users
432   - Start Users
433   - Start Traffcounter
434   - Start Plugins
435   - Start pinger
436   - Set signal nandlers
437   - Fork and exit
438  * */
439
440 SETTINGS_IMPL * settings = NULL;
441 STORE * dataStore = NULL;
442 TARIFFS_IMPL * tariffs = NULL;
443 ADMINS_IMPL * admins = NULL;
444 USERS_IMPL * users = NULL;
445 TRAFFCOUNTER_IMPL * traffCnt = NULL;
446 int msgID = -11;
447
448     {
449     STG_LOGGER & WriteServLog = GetStgLogger();
450     WriteServLog.SetLogFileName("/var/log/stargazer.log");
451     }
452
453 vector<MODULE_SETTINGS> modSettings;
454 list<PLUGIN_RUNNER> modules;
455
456 list<PLUGIN_RUNNER>::iterator modIter;
457
458 if (getuid())
459     {
460     printf("You must be root. Exit.\n");
461     exit(1);
462     }
463
464 if (argc == 2)
465     settings = new SETTINGS_IMPL(argv[1]);
466 else
467     settings = new SETTINGS_IMPL();
468
469 if (settings->ReadSettings())
470     {
471     STG_LOGGER & WriteServLog = GetStgLogger();
472
473     if (settings->GetLogFileName() != "")
474         WriteServLog.SetLogFileName(settings->GetLogFileName());
475
476     WriteServLog("ReadSettings error. %s", settings->GetStrError().c_str());
477     exit(1);
478     }
479
480 #ifndef NO_DAEMON
481 string startFile(settings->GetConfDir() + START_FILE);
482 #endif
483
484 if (ForkAndWait(settings->GetConfDir()) < 0)
485     {
486     STG_LOGGER & WriteServLog = GetStgLogger();
487     WriteServLog("Fork error!");
488     exit(1);
489     }
490
491 STG_LOGGER & WriteServLog = GetStgLogger();
492 WriteServLog.SetLogFileName(settings->GetLogFileName());
493 WriteServLog("Stg v. %s", SERVER_VERSION);
494
495 for (size_t i = 0; i < settings->GetExecutersNum(); i++)
496     {
497     int ret = StartScriptExecuter(argv[0], settings->GetExecMsgKey(), &msgID, settings);
498     if (ret < 0)
499         {
500         STG_LOGGER & WriteServLog = GetStgLogger();
501         WriteServLog("Start Script Executer error!");
502         return 1;
503         }
504     if (ret == 1)
505         {
506         // Stopping child
507         return 0;
508         }
509     }
510
511 PIDFile pidFile(settings->GetPIDFileName());
512
513 StartTimer();
514 WaitTimer();
515 if (!IsStgTimerRunning())
516     {
517     printfd(__FILE__, "Timer thread not started in 1 sec!\n");
518     WriteServLog("Timer thread not started in 1 sec!");
519     }
520
521 EVENT_LOOP & loop(EVENT_LOOP_SINGLETON::GetInstance());
522
523 STORE_LOADER storeLoader(*settings);
524 if (storeLoader.Load())
525     {
526     WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
527     goto exitLblNotStarted;
528     }
529
530 if (loop.Start())
531     {
532     WriteServLog("Event loop not started.");
533     goto exitLblNotStarted;
534     }
535
536 dataStore = storeLoader.GetStore();
537 WriteServLog("Storage plugin: %s. Loading successfull.", dataStore->GetVersion().c_str());
538
539 tariffs = new TARIFFS_IMPL(dataStore);
540 admins = new ADMINS_IMPL(dataStore);
541 users = new USERS_IMPL(settings, dataStore, tariffs, admins->GetSysAdmin());
542 traffCnt = new TRAFFCOUNTER_IMPL(users, tariffs, settings->GetRulesFileName());
543 traffCnt->SetMonitorDir(settings->GetMonitorDir());
544
545 modSettings = settings->GetModulesSettings();
546
547 for (size_t i = 0; i < modSettings.size(); i++)
548     {
549     string modulePath = settings->GetModulesPath();
550     modulePath += "/mod_";
551     modulePath += modSettings[i].moduleName;
552     modulePath += ".so";
553     printfd(__FILE__, "Module: %s\n", modulePath.c_str());
554     modules.push_back(
555         PLUGIN_RUNNER(modulePath,
556                       modSettings[i],
557                       admins,
558                       tariffs,
559                       users,
560                       traffCnt,
561                       dataStore,
562                       settings)
563         );
564     }
565
566 modIter = modules.begin();
567
568 while (modIter != modules.end())
569     {
570     //Loading modules
571     if (modIter->Load())
572         {
573         WriteServLog("Error: %s",
574                      modIter->GetStrError().c_str());
575         goto exitLblNotStarted;
576         }
577     ++modIter;
578     }
579
580 //Start section
581 if (users->Start())
582     {
583     goto exitLblNotStarted;
584     }
585 WriteServLog("Users started successfully.");
586
587 if (traffCnt->Start())
588     {
589     goto exitLblNotStarted;
590     }
591 WriteServLog("Traffcounter started successfully.");
592
593 //Sort by start order
594 modules.sort(StartModCmp);
595 modIter = modules.begin();
596
597 while (modIter != modules.end())
598     {
599     if (modIter->Start())
600         {
601         WriteServLog("Error: %s",
602                      modIter->GetStrError().c_str());
603         //printfd(__FILE__, "Error: %s\n", capRunner.GetStrError().c_str());
604         goto exitLbl;
605         }
606     WriteServLog("Module: '%s'. Start successfull.", modIter->GetPlugin()->GetVersion().c_str());
607     ++modIter;
608     }
609 SetSignalHandlers();
610
611 srandom(stgTime);
612
613 /*
614  * Note that an implementation in which nice returns the new nice value
615  * can legitimately return -1.   To  reliably  detect  an  error,  set
616  * errno to 0 before the call, and check its value when nice returns -1.
617  *
618  *
619  * (c) man 2 nice
620  */
621 errno = 0;
622 if (nice(-19) && errno) {
623     printfd(__FILE__, "nice failed: '%s'\n", strerror(errno));
624     WriteServLog("nice failed: '%s'", strerror(errno));
625 }
626
627 WriteServLog("Stg started successfully.");
628 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
629
630 #ifndef NO_DAEMON
631 creat(startFile.c_str(), S_IRUSR);
632 #endif
633
634 while (nonstop.GetStatus())
635     {
636     if (needRulesReloading)
637         {
638         needRulesReloading = false;
639         traffCnt->Reload();
640
641         modIter = modules.begin();
642         for (; modIter != modules.end(); ++modIter)
643             {
644             if (modIter->Reload())
645                 {
646                 WriteServLog("Error reloading %s ('%s')", modIter->GetPlugin()->GetVersion().c_str(),
647                                                           modIter->GetStrError().c_str());
648                 printfd(__FILE__, "Error reloading %s ('%s')\n", modIter->GetPlugin()->GetVersion().c_str(),
649                                                                  modIter->GetStrError().c_str());
650                 }
651             }
652         }
653     stgUsleep(100000);
654     }
655
656 exitLbl:
657
658 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
659
660 //Sort by start order
661 modules.sort(StopModCmp);
662 modIter = modules.begin();
663 while (modIter != modules.end())
664     {
665     std::string name = modIter->GetFileName();
666     printfd(__FILE__, "Stopping module '%s'\n", name.c_str());
667     if (modIter->Stop())
668         {
669         WriteServLog("Module \'%s\': Error: %s",
670                      modIter->GetPlugin()->GetVersion().c_str(),
671                      modIter->GetStrError().c_str());
672         printfd(__FILE__, "Failed to stop module '%s'\n", name.c_str());
673         //printfd(__FILE__, "Error: %s\n", capRunner.GetStrError().c_str());
674         //goto exitLbl;
675         }
676     WriteServLog("Module: \'%s\'. Stop successfull.", modIter->GetPlugin()->GetVersion().c_str());
677     ++modIter;
678     }
679
680 if (loop.Stop())
681     {
682     WriteServLog("Event loop not stopped.");
683     }
684
685 exitLblNotStarted:
686
687 modIter = modules.begin();
688 while (modIter != modules.end())
689     {
690     std::string name = modIter->GetFileName();
691     printfd(__FILE__, "Unloading module '%s'\n", name.c_str());
692     if (modIter->Unload())
693         {
694         WriteServLog("Module \'%s\': Error: %s",
695                      name.c_str(),
696                      modIter->GetStrError().c_str());
697         printfd(__FILE__, "Failed to unload module '%s'\n", name.c_str());
698         }
699     ++modIter;
700     }
701
702 if (traffCnt)
703     {
704     traffCnt->Stop();
705     WriteServLog("Traffcounter: Stop successfull.");
706     }
707
708 if (users)
709     {
710     users->Stop();
711     WriteServLog("Users: Stop successfull.");
712     }
713
714 sleep(1);
715 int res = msgctl(msgID, IPC_RMID, NULL);
716 if (res)
717     WriteServLog("Queue was not removed. id=%d", msgID);
718 else
719     WriteServLog("Queue removed successfully.");
720
721 KillExecuters();
722
723 StopStgTimer();
724 WriteServLog("StgTimer: Stop successfull.");
725
726 delete traffCnt;
727 delete users;
728 delete admins;
729 delete tariffs;
730 delete settings;
731
732 WriteServLog("Stg stopped successfully.");
733 WriteServLog("---------------------------------------------");
734
735 return 0;
736 }
737 //-----------------------------------------------------------------------------