]> git.stg.codes - stg.git/blob - projects/stargazer/main.cpp
New signal handling infrastructure. Prevent unloading running module.
[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/conffiles.h"
50 #include "stg/version.h"
51 #include "stg/pinger.h"
52 #include "stg_timer.h"
53 #include "settings_impl.h"
54 #include "users_impl.h"
55 #include "admins_impl.h"
56 #include "tariffs_impl.h"
57 #include "services_impl.h"
58 #include "corps_impl.h"
59 #include "traffcounter_impl.h"
60 #include "plugin_runner.h"
61 #include "store_loader.h"
62 #include "pidfile.h"
63 #include "eventloop.h"
64
65 using namespace std;
66
67 #ifdef DEBUG
68     #define MAIN_DEBUG (1)
69     #define NO_DAEMON  (1)
70 #endif
71
72 #define START_FILE "/._ST_ART_ED_"
73
74 set<pid_t> executersPid;
75 static pid_t stgChildPid;
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 static void StartTimer()
89 {
90 STG_LOGGER & WriteServLog = GetStgLogger();
91
92 if (RunStgTimer())
93     {
94     WriteServLog("Cannot start timer. Fatal.");
95     //printfd(__FILE__, "Cannot start timer. Fatal.\n");
96     exit(1);
97     }
98 else
99     {
100     WriteServLog("Timer thread started successfully.");
101     //printfd(__FILE__, "Timer thread started successfully.\n");
102     }
103 }
104 //-----------------------------------------------------------------------------
105 int StartScriptExecuter(char * procName, int msgKey, int * msgID, SETTINGS_IMPL * settings)
106 {
107 STG_LOGGER & WriteServLog = GetStgLogger();
108
109 if (*msgID == -11)   // If msgID == -11 - first call. Create queue
110     {
111     for (int i = 0; i < 2; i++)
112         {
113         *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
114
115         if (*msgID == -1)
116             {
117             *msgID = msgget(msgKey, 0);
118             if (*msgID == -1)
119                 {
120                 WriteServLog("Message queue not created.");
121                 return -1;
122                 }
123             else
124                 {
125                 msgctl(*msgID, IPC_RMID, NULL);
126                 }
127             }
128         else
129             {
130             WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
131             break;
132             }
133         }
134     }
135
136 pid_t executerPid = fork();
137
138 switch (executerPid)
139     {
140     case -1:
141         WriteServLog("Fork error!");
142         return -1;
143
144     case 0:
145         delete settings;
146         Executer(*msgID, executerPid, procName);
147         return 1;
148
149     default:
150         if (executersPid.empty()) {
151             Executer(*msgID, executerPid, NULL);
152         }
153         executersPid.insert(executerPid);
154     }
155 return 0;
156 }
157 //-----------------------------------------------------------------------------
158 #ifndef NO_DAEMON
159 int ForkAndWait(const string & confDir)
160 #else
161 int ForkAndWait(const string &)
162 #endif
163 {
164 #ifndef NO_DAEMON
165 stgChildPid = fork();
166 string startFile = confDir + START_FILE;
167 unlink(startFile.c_str());
168
169 switch (stgChildPid)
170     {
171     case -1:
172         return -1;
173         break;
174
175     case 0:
176         close(1);
177         close(2);
178         setsid();
179         break;
180
181     default:
182         struct timespec ts = {0, 200000000};
183         for (int i = 0; i < 120 * 5; i++)
184             {
185             if (access(startFile.c_str(), F_OK) == 0)
186                 {
187                 unlink(startFile.c_str());
188                 exit(0);
189                 }
190
191             nanosleep(&ts, NULL);
192             }
193         unlink(startFile.c_str());
194         exit(1);
195         break;
196     }
197 #endif
198 return 0;
199 }
200 //-----------------------------------------------------------------------------
201 void KillExecuters()
202 {
203 set<pid_t>::iterator pid;
204 pid = executersPid.begin();
205 while (pid != executersPid.end())
206     {
207     printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
208     kill(*pid, SIGUSR1);
209     ++pid;
210     }
211 }
212 //-----------------------------------------------------------------------------
213 int main(int argc, char * argv[])
214 {
215 SETTINGS_IMPL * settings = NULL;
216 STORE * dataStore = NULL;
217 TARIFFS_IMPL * tariffs = NULL;
218 ADMINS_IMPL * admins = NULL;
219 USERS_IMPL * users = NULL;
220 TRAFFCOUNTER_IMPL * traffCnt = NULL;
221 SERVICES_IMPL * services = NULL;
222 CORPORATIONS_IMPL * corps = NULL;
223 int msgID = -11;
224
225     {
226     STG_LOGGER & WriteServLog = GetStgLogger();
227     WriteServLog.SetLogFileName("/var/log/stargazer.log");
228     }
229
230 vector<MODULE_SETTINGS> modSettings;
231 list<PLUGIN_RUNNER> modules;
232
233 list<PLUGIN_RUNNER>::iterator modIter;
234
235 if (getuid())
236     {
237     printf("You must be root. Exit.\n");
238     exit(1);
239     }
240
241 if (argc == 2)
242     settings = new SETTINGS_IMPL(argv[1]);
243 else
244     settings = new SETTINGS_IMPL();
245
246 if (settings->ReadSettings())
247     {
248     STG_LOGGER & WriteServLog = GetStgLogger();
249
250     if (settings->GetLogFileName() != "")
251         WriteServLog.SetLogFileName(settings->GetLogFileName());
252
253     WriteServLog("ReadSettings error. %s", settings->GetStrError().c_str());
254     exit(1);
255     }
256
257 #ifndef NO_DAEMON
258 string startFile(settings->GetConfDir() + START_FILE);
259 #endif
260
261 if (ForkAndWait(settings->GetConfDir()) < 0)
262     {
263     STG_LOGGER & WriteServLog = GetStgLogger();
264     WriteServLog("Fork error!");
265     exit(1);
266     }
267
268 STG_LOGGER & WriteServLog = GetStgLogger();
269 WriteServLog.SetLogFileName(settings->GetLogFileName());
270 WriteServLog("Stg v. %s", SERVER_VERSION);
271
272 for (size_t i = 0; i < settings->GetExecutersNum(); i++)
273     {
274     int ret = StartScriptExecuter(argv[0], settings->GetExecMsgKey(), &msgID, settings);
275     if (ret < 0)
276         {
277         STG_LOGGER & WriteServLog = GetStgLogger();
278         WriteServLog("Start Script Executer error!");
279         return 1;
280         }
281     if (ret == 1)
282         {
283         // Stopping child
284         return 0;
285         }
286     }
287
288 PIDFile pidFile(settings->GetPIDFileName());
289
290 StartTimer();
291 WaitTimer();
292 if (!IsStgTimerRunning())
293     {
294     printfd(__FILE__, "Timer thread not started in 1 sec!\n");
295     WriteServLog("Timer thread not started in 1 sec!");
296     }
297
298 EVENT_LOOP & loop(EVENT_LOOP_SINGLETON::GetInstance());
299
300 STORE_LOADER storeLoader(*settings);
301 if (storeLoader.Load())
302     {
303     WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
304     goto exitLblNotStarted;
305     }
306
307 if (loop.Start())
308     {
309     WriteServLog("Event loop not started.");
310     goto exitLblNotStarted;
311     }
312
313 dataStore = storeLoader.GetStore();
314 WriteServLog("Storage plugin: %s. Loading successfull.", dataStore->GetVersion().c_str());
315
316 tariffs = new TARIFFS_IMPL(dataStore);
317 admins = new ADMINS_IMPL(dataStore);
318 users = new USERS_IMPL(settings, dataStore, tariffs, admins->GetSysAdmin());
319 traffCnt = new TRAFFCOUNTER_IMPL(users, settings->GetRulesFileName());
320 services = new SERVICES_IMPL(dataStore);
321 corps = new CORPORATIONS_IMPL(dataStore);
322 traffCnt->SetMonitorDir(settings->GetMonitorDir());
323
324 modSettings = settings->GetModulesSettings();
325
326 for (size_t i = 0; i < modSettings.size(); i++)
327     {
328     string modulePath = settings->GetModulesPath();
329     modulePath += "/mod_";
330     modulePath += modSettings[i].moduleName;
331     modulePath += ".so";
332     printfd(__FILE__, "Module: %s\n", modulePath.c_str());
333     modules.push_back(
334         PLUGIN_RUNNER(modulePath,
335                       modSettings[i],
336                       admins,
337                       tariffs,
338                       users,
339                       services,
340                       corps,
341                       traffCnt,
342                       dataStore,
343                       settings)
344         );
345     }
346
347 modIter = modules.begin();
348
349 while (modIter != modules.end())
350     {
351     if (modIter->Load())
352         {
353         WriteServLog("Error: %s",
354                      modIter->GetStrError().c_str());
355         goto exitLblNotStarted;
356         }
357     ++modIter;
358     }
359
360 if (users->Start())
361     {
362     goto exitLblNotStarted;
363     }
364 WriteServLog("Users started successfully.");
365
366 if (traffCnt->Start())
367     {
368     goto exitLblNotStarted;
369     }
370 WriteServLog("Traffcounter started successfully.");
371
372 //Sort by start order
373 modules.sort(StartModCmp);
374 modIter = modules.begin();
375
376 while (modIter != modules.end())
377     {
378     if (modIter->Start())
379         {
380         WriteServLog("Error: %s",
381                      modIter->GetStrError().c_str());
382         goto exitLbl;
383         }
384     WriteServLog("Module: '%s'. Start successfull.", modIter->GetPlugin()->GetVersion().c_str());
385     ++modIter;
386     }
387
388 srandom(stgTime);
389
390 WriteServLog("Stg started successfully.");
391 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
392
393 #ifndef NO_DAEMON
394 creat(startFile.c_str(), S_IRUSR);
395 #endif
396
397 while (true)
398     {
399     sigset_t signalSet;
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 //-----------------------------------------------------------------------------