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