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