]> git.stg.codes - stg.git/blob - projects/stargazer/main.cpp
Introduced logger for plugins.
[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 loading module '%s': %s",
367                      modIter->GetPlugin()->GetVersion().c_str(),
368                      modIter->GetStrError().c_str());
369         goto exitLblNotStarted;
370         }
371     ++modIter;
372     }
373
374 if (users->Start())
375     {
376     goto exitLblNotStarted;
377     }
378 WriteServLog("Users started successfully.");
379
380 if (traffCnt->Start())
381     {
382     goto exitLblNotStarted;
383     }
384 WriteServLog("Traffcounter started successfully.");
385
386 //Sort by start order
387 modules.sort(StartModCmp);
388 modIter = modules.begin();
389
390 while (modIter != modules.end())
391     {
392     if (modIter->Start())
393         {
394         WriteServLog("Error starting module '%s': %s",
395                      modIter->GetPlugin()->GetVersion().c_str(),
396                      modIter->GetStrError().c_str());
397         goto exitLbl;
398         }
399     WriteServLog("Module: '%s'. Start successfull.", modIter->GetPlugin()->GetVersion().c_str());
400     ++modIter;
401     }
402
403 srandom(stgTime);
404
405 WriteServLog("Stg started successfully.");
406 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
407
408 #ifndef NO_DAEMON
409 creat(startFile.c_str(), S_IRUSR);
410 #endif
411
412 while (true)
413     {
414     sigfillset(&signalSet);
415     int sig = 0;
416     sigwait(&signalSet, &sig);
417     bool stop = false;
418     int status;
419     pid_t childPid;
420     set<pid_t>::iterator it;
421     switch (sig)
422         {
423         case SIGHUP:
424             traffCnt->Reload();
425             modIter = modules.begin();
426             for (; modIter != modules.end(); ++modIter)
427                 {
428                 if (modIter->Reload())
429                     {
430                     WriteServLog("Error reloading module '%s': '%s'", modIter->GetPlugin()->GetVersion().c_str(),
431                                                               modIter->GetStrError().c_str());
432                     printfd(__FILE__, "Error reloading module '%s': '%s'\n", modIter->GetPlugin()->GetVersion().c_str(),
433                                                                      modIter->GetStrError().c_str());
434                     }
435                 }
436             break;
437         case SIGTERM:
438             stop = true;
439             break;
440         case SIGINT:
441             stop = true;
442             break;
443         case SIGPIPE:
444             WriteServLog("Broken pipe!");
445             break;
446         case SIGCHLD:
447             childPid = waitpid(-1, &status, WNOHANG);
448
449             it = executersPid.find(childPid);
450             if (it != executersPid.end())
451                 {
452                 executersPid.erase(it);
453                 if (executersPid.empty())
454                     stop = true;
455                 }
456             break;
457         default:
458             WriteServLog("Ignore signel %d", sig);
459             break;
460         }
461     if (stop)
462         break;
463     }
464
465 exitLbl:
466
467 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
468
469 //Sort by start order
470 modules.sort(StopModCmp);
471 modIter = modules.begin();
472 while (modIter != modules.end())
473     {
474     std::string name = modIter->GetFileName();
475     printfd(__FILE__, "Stopping module '%s'\n", name.c_str());
476     if (modIter->Stop())
477         {
478         WriteServLog("Error stopping module '%s': %s",
479                      modIter->GetPlugin()->GetVersion().c_str(),
480                      modIter->GetStrError().c_str());
481         printfd(__FILE__, "Error stopping module '%s': '%s'\n", modIter->GetPlugin()->GetVersion().c_str(), modIter->GetStrError().c_str());
482         }
483     else
484         {
485         WriteServLog("Module: '%s'. Stop successfull.", modIter->GetPlugin()->GetVersion().c_str());
486         }
487     ++modIter;
488     }
489
490 if (loop.Stop())
491     {
492     WriteServLog("Event loop not stopped.");
493     }
494
495 exitLblNotStarted:
496
497 modIter = modules.begin();
498 while (modIter != modules.end())
499     {
500     std::string name = modIter->GetFileName();
501     if (modIter->IsRunning())
502         {
503         printfd(__FILE__, "Passing module '%s' `cause it's still running\n", name.c_str());
504         }
505     else
506         {
507         printfd(__FILE__, "Unloading module '%s'\n", name.c_str());
508         if (modIter->Unload())
509             {
510             WriteServLog("Error unloading module '%s': '%s'",
511                          modIter->GetPlugin()->GetVersion().c_str(),
512                          modIter->GetStrError().c_str());
513             printfd(__FILE__, "Error unloading module '%s': '%s'\n", modIter->GetPlugin()->GetVersion().c_str(), modIter->GetStrError().c_str());
514             }
515         }
516     ++modIter;
517     }
518
519 if (traffCnt)
520     {
521     traffCnt->Stop();
522     WriteServLog("Traffcounter: Stop successfull.");
523     }
524
525 if (users)
526     {
527     users->Stop();
528     WriteServLog("Users: Stop successfull.");
529     }
530
531 sleep(1);
532 int res = msgctl(msgID, IPC_RMID, NULL);
533 if (res)
534     WriteServLog("Queue was not removed. id=%d", msgID);
535 else
536     WriteServLog("Queue removed successfully.");
537
538 KillExecuters();
539
540 StopStgTimer();
541 WriteServLog("StgTimer: Stop successfull.");
542
543 delete corps;
544 delete services;
545 delete traffCnt;
546 delete users;
547 delete admins;
548 delete tariffs;
549 delete settings;
550
551 WriteServLog("Stg stopped successfully.");
552 WriteServLog("---------------------------------------------");
553
554 return 0;
555 }
556 //-----------------------------------------------------------------------------