X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/4271ab433cd55bbd2612292bcf39e4dc3d7274f1..0907aa4037b12b6b88ee24495d4577a064d4f8db:/projects/stargazer/main.cpp diff --git a/projects/stargazer/main.cpp b/projects/stargazer/main.cpp new file mode 100644 index 00000000..825cba58 --- /dev/null +++ b/projects/stargazer/main.cpp @@ -0,0 +1,405 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Boris Mikhailenko + */ + +#include "store_loader.h" +#include "plugin_mgr.h" +#include "plugin_runner.h" +#include "users_impl.h" +#include "admins_impl.h" +#include "tariffs_impl.h" +#include "services_impl.h" +#include "corps_impl.h" +#include "traffcounter_impl.h" +#include "settings_impl.h" +#include "pidfile.h" +#include "eventloop.h" +#include "stg_timer.h" + +#include "stg/user.h" +#include "stg/common.h" +#include "stg/plugin.h" +#include "stg/logger.h" +#include "stg/scriptexecuter.h" +#include "stg/version.h" + +#include +#include +#include +#include +#include +#include +#include // srandom, exit + +#include +#include +#include +#include +#include +#include // S_IRUSR +#include // create + +#ifdef DEBUG + #define NO_DAEMON (1) +#endif + +#define START_FILE "/._ST_ART_ED_" + +using STG::SettingsImpl; +using STG::AdminsImpl; +using STG::TraffCounterImpl; +using STG::UsersImpl; +using STG::TariffsImpl; +using STG::ServicesImpl; +using STG::CorporationsImpl; +using STG::StoreLoader; + +namespace +{ +std::set executers; + +void StartTimer(); +int StartScriptExecuter(char* procName, int msgKey, int* msgID); +int ForkAndWait(const std::string& confDir); +void KillExecuters(); + +//----------------------------------------------------------------------------- +void StartTimer() +{ + auto& WriteServLog = STG::Logger::get(); + + if (RunStgTimer()) + { + WriteServLog("Cannot start timer. Fatal."); + exit(1); + } + else + WriteServLog("Timer thread started successfully."); +} +//----------------------------------------------------------------------------- +#if defined(LINUX) || defined(DARWIN) +int StartScriptExecuter(char* procName, int msgKey, int* msgID) +#else +int StartScriptExecuter(char*, int msgKey, int* msgID) +#endif +{ + auto& WriteServLog = STG::Logger::get(); + + if (*msgID == -11) // If msgID == -11 - first call. Create queue + { + for (int i = 0; i < 2; i++) + { + *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600); + + if (*msgID == -1) + { + *msgID = msgget(msgKey, 0); + if (*msgID == -1) + { + WriteServLog("Message queue not created."); + return -1; + } + else + msgctl(*msgID, IPC_RMID, NULL); + } + else + { + WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID); + break; + } + } + } + + const auto pid = fork(); + + switch (pid) + { + case -1: + WriteServLog("Fork error!"); + return -1; + + case 0: +#if defined(LINUX) || defined(DARWIN) + Executer(*msgID, pid, procName); +#else + Executer(*msgID, pid); +#endif + return 1; + + default: + if (executers.empty()) { +#if defined(LINUX) || defined(DARWIN) + Executer(*msgID, pid, NULL); +#else + Executer(*msgID, pid); +#endif + } + executers.insert(pid); + } + return 0; +} +//----------------------------------------------------------------------------- +#ifndef NO_DAEMON +int ForkAndWait(const std::string& confDir) +#else +int ForkAndWait(const std::string&) +#endif +{ +#ifndef NO_DAEMON + const auto pid = fork(); + const auto startFile = confDir + START_FILE; + unlink(startFile.c_str()); + + switch (pid) + { + case -1: + return -1; + break; + + case 0: + close(1); + close(2); + setsid(); + break; + + default: + struct timespec ts = {0, 200000000}; + for (int i = 0; i < 120 * 5; i++) + { + if (access(startFile.c_str(), F_OK) == 0) + { + unlink(startFile.c_str()); + exit(0); + } + + nanosleep(&ts, NULL); + } + unlink(startFile.c_str()); + exit(1); + break; + } +#endif + return 0; +} +//----------------------------------------------------------------------------- +void KillExecuters() +{ + auto pid = executers.begin(); + while (pid != executers.end()) + { + printfd(__FILE__, "KillExecuters pid=%d\n", *pid); + kill(*pid, SIGUSR1); + ++pid; + } +} +//----------------------------------------------------------------------------- +} // namespace anonymous +//----------------------------------------------------------------------------- +int main(int argc, char* argv[]) +{ + int msgID = -11; + + STG::Logger::get().setFileName("/var/log/stargazer.log"); + + if (getuid()) + { + printf("You must be root. Exit.\n"); + return 1; + } + + SettingsImpl settings(argc == 2 ? argv[1] : ""); + + if (settings.ReadSettings()) + { + auto& WriteServLog = STG::Logger::get(); + + if (settings.GetLogFileName() != "") + WriteServLog.setFileName(settings.GetLogFileName()); + + WriteServLog("ReadSettings error. %s", settings.GetStrError().c_str()); + return -1; + } + +#ifndef NO_DAEMON + const auto startFile = settings.GetConfDir() + START_FILE; +#endif + + if (ForkAndWait(settings.GetConfDir()) < 0) + { + STG::Logger::get()("Fork error!"); + return -1; + } + + auto& WriteServLog = STG::Logger::get(); + WriteServLog.setFileName(settings.GetLogFileName()); + WriteServLog("Stg v. %s", SERVER_VERSION); + + for (size_t i = 0; i < settings.GetExecutersNum(); i++) + { + auto ret = StartScriptExecuter(argv[0], settings.GetExecMsgKey(), &msgID); + if (ret < 0) + { + STG::Logger::get()("Start Script Executer error!"); + return -1; + } + if (ret == 1) + return 0; + } + + PIDFile pidFile(settings.GetPIDFileName()); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGHUP, &sa, NULL); // Apparently FreeBSD ignores SIGHUP by default when launched from rc.d at bot time. + + sigset_t signalSet; + sigfillset(&signalSet); + pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + + StartTimer(); + WaitTimer(); + if (!IsStgTimerRunning()) + { + printfd(__FILE__, "Timer thread not started in 1 sec!\n"); + WriteServLog("Timer thread not started in 1 sec!"); + return -1; + } + + auto& loop = EVENT_LOOP_SINGLETON::GetInstance(); + + StoreLoader storeLoader(settings); + if (storeLoader.load()) + { + printfd(__FILE__, "Storage plugin: '%s'\n", storeLoader.GetStrError().c_str()); + WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str()); + return -1; + } + + if (loop.Start()) + { + printfd(__FILE__, "Event loop not started.\n"); + WriteServLog("Event loop not started."); + return -1; + } + + auto& store = storeLoader.get(); + WriteServLog("Storage plugin: %s. Loading successfull.", store.GetVersion().c_str()); + + AdminsImpl admins(store); + TariffsImpl tariffs(&store); + ServicesImpl services(&store); + CorporationsImpl corps(&store); + UsersImpl users(&settings, &store, &tariffs, services, admins.sysAdmin()); + TraffCounterImpl traffCnt(&users, settings.GetRulesFileName()); + traffCnt.SetMonitorDir(settings.GetMonitorDir()); + + if (users.Start()) + return -1; + + WriteServLog("Users started successfully."); + + if (traffCnt.Start()) + return -1; + + WriteServLog("Traffcounter started successfully."); + + STG::PluginManager manager(settings, store, admins, tariffs, services, corps, users, traffCnt); + + srandom(static_cast(stgTime)); + + WriteServLog("Stg started successfully."); + WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++"); + +#ifndef NO_DAEMON + creat(startFile.c_str(), S_IRUSR); +#endif + + bool running = true; + while (running) + { + sigfillset(&signalSet); + int sig = 0; + sigwait(&signalSet, &sig); + int status; + switch (sig) + { + case SIGHUP: + { + SettingsImpl newSettings(settings); + if (newSettings.ReadSettings()) + WriteServLog("ReadSettings error. %s", newSettings.GetStrError().c_str()); + else + settings = newSettings; + WriteServLog.setFileName(settings.GetLogFileName()); + traffCnt.Reload(); + manager.reload(settings); + break; + } + case SIGTERM: + running = false; + break; + case SIGINT: + running = false; + break; + case SIGPIPE: + WriteServLog("Broken pipe!"); + break; + case SIGCHLD: + executers.erase(waitpid(-1, &status, WNOHANG)); + if (executers.empty()) + running = false; + break; + default: + WriteServLog("Ignore signal %d", sig); + break; + } + } + + WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++"); + + manager.stop(); + + if (loop.Stop()) + WriteServLog("Event loop not stopped."); + + if (!traffCnt.Stop()) + WriteServLog("Traffcounter: Stop successfull."); + + if (!users.Stop()) + WriteServLog("Users: Stop successfull."); + + sleep(1); + int res = msgctl(msgID, IPC_RMID, NULL); + if (res) + WriteServLog("Queue was not removed. id=%d", msgID); + else + WriteServLog("Queue removed successfully."); + + KillExecuters(); + + StopStgTimer(); + WriteServLog("StgTimer: Stop successfull."); + + WriteServLog("Stg stopped successfully."); + WriteServLog("---------------------------------------------"); + + return 0; +} +//-----------------------------------------------------------------------------