mirror of
https://github.com/anope/anope.git
synced 2026-07-06 19:23:15 +02:00
d33a0f75a5
cleanup, and allow protocol mods to depend on each other
239 lines
5.7 KiB
C++
239 lines
5.7 KiB
C++
/* Services -- main source file.
|
|
*
|
|
* (C) 2003-2012 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*
|
|
*/
|
|
|
|
#include "services.h"
|
|
#include "timers.h"
|
|
#include "config.h"
|
|
#include "bots.h"
|
|
#include "signals.h"
|
|
#include "socketengine.h"
|
|
#include "uplink.h"
|
|
|
|
#ifndef _WIN32
|
|
#include <limits.h>
|
|
#else
|
|
#include <process.h>
|
|
#endif
|
|
|
|
/* Command-line options: */
|
|
int Anope::Debug = 0;
|
|
bool Anope::ReadOnly = false, Anope::NoFork = false, Anope::NoThird = false, Anope::NoExpire = false, Anope::ProtocolDebug = false;
|
|
Anope::string Anope::ServicesDir;
|
|
Anope::string Anope::ServicesBin;
|
|
|
|
int Anope::ReturnValue = 0;
|
|
bool Anope::Quitting = false;
|
|
bool Anope::Restarting = false;
|
|
Anope::string Anope::QuitReason;
|
|
|
|
static Anope::string BinaryDir; /* Full path to services bin directory */
|
|
|
|
time_t Anope::StartTime = time(NULL);
|
|
time_t Anope::CurTime = time(NULL);
|
|
|
|
int Anope::CurrentUplink = -1;
|
|
|
|
class UpdateTimer : public Timer
|
|
{
|
|
public:
|
|
UpdateTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
|
|
|
|
void Tick(time_t)
|
|
{
|
|
Anope::SaveDatabases();
|
|
}
|
|
};
|
|
|
|
void Anope::SaveDatabases()
|
|
{
|
|
if (Anope::ReadOnly)
|
|
return;
|
|
|
|
EventReturn MOD_RESULT;
|
|
FOREACH_RESULT(I_OnSaveDatabase, OnSaveDatabase());
|
|
Log(LOG_DEBUG) << "Saving databases";
|
|
}
|
|
|
|
std::vector<Signal *> Signal::SignalHandlers;
|
|
|
|
void Signal::SignalHandler(int signal)
|
|
{
|
|
for (unsigned i = 0, j = SignalHandlers.size(); i < j; ++i)
|
|
if (SignalHandlers[i]->signal == signal)
|
|
SignalHandlers[i]->Notify();
|
|
}
|
|
|
|
Signal::Signal(int s) : Pipe(), signal(s)
|
|
{
|
|
memset(&this->old, 0, sizeof(this->old));
|
|
|
|
this->action.sa_flags = 0;
|
|
sigemptyset(&this->action.sa_mask);
|
|
this->action.sa_handler = SignalHandler;
|
|
|
|
if (sigaction(s, &this->action, &this->old) == -1)
|
|
throw CoreException("Unable to install signal " + stringify(s) + ": " + Anope::LastError());
|
|
|
|
SignalHandlers.push_back(this);
|
|
}
|
|
|
|
Signal::~Signal()
|
|
{
|
|
std::vector<Signal *>::iterator it = std::find(SignalHandlers.begin(), SignalHandlers.end(), this);
|
|
if (it != SignalHandlers.end())
|
|
SignalHandlers.erase(it);
|
|
|
|
sigaction(this->signal, &this->old, NULL);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/** The following comes from InspIRCd to get the full path of the Anope executable
|
|
*/
|
|
static Anope::string GetFullProgDir(const Anope::string &argv0)
|
|
{
|
|
char buffer[PATH_MAX];
|
|
#ifdef _WIN32
|
|
/* Windows has specific API calls to get the EXE path that never fail.
|
|
* For once, Windows has something of use, compared to the POSIX code
|
|
* for this, this is positively neato.
|
|
*/
|
|
if (GetModuleFileName(NULL, buffer, PATH_MAX))
|
|
{
|
|
Anope::string fullpath = buffer;
|
|
Anope::string::size_type n = fullpath.rfind("\\");
|
|
Anope::ServicesBin = fullpath.substr(n + 1, fullpath.length());
|
|
return fullpath.substr(0, n);
|
|
}
|
|
#else
|
|
// Get the current working directory
|
|
if (getcwd(buffer, PATH_MAX))
|
|
{
|
|
Anope::string remainder = argv0;
|
|
|
|
Anope::ServicesBin = remainder;
|
|
Anope::string::size_type n = Anope::ServicesBin.rfind("/");
|
|
Anope::string fullpath;
|
|
if (Anope::ServicesBin[0] == '/')
|
|
fullpath = Anope::ServicesBin.substr(0, n);
|
|
else
|
|
fullpath = Anope::string(buffer) + "/" + Anope::ServicesBin.substr(0, n);
|
|
Anope::ServicesBin = Anope::ServicesBin.substr(n + 1, remainder.length());
|
|
return fullpath;
|
|
}
|
|
#endif
|
|
return "/";
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Main routine. (What does it look like? :-) ) */
|
|
|
|
int main(int ac, char **av, char **envp)
|
|
{
|
|
BinaryDir = GetFullProgDir(av[0]);
|
|
if (BinaryDir[BinaryDir.length() - 1] == '.')
|
|
BinaryDir = BinaryDir.substr(0, BinaryDir.length() - 2);
|
|
|
|
#ifdef _WIN32
|
|
Anope::string::size_type n = BinaryDir.rfind('\\');
|
|
#else
|
|
Anope::string::size_type n = BinaryDir.rfind('/');
|
|
#endif
|
|
Anope::ServicesDir = BinaryDir.substr(0, n);
|
|
|
|
/* Clean out the module runtime directory prior to running, just in case files were left behind during a previous run */
|
|
ModuleManager::CleanupRuntimeDirectory();
|
|
|
|
#ifdef _WIN32
|
|
OnStartup();
|
|
#endif
|
|
|
|
try
|
|
{
|
|
/* General initialization first */
|
|
Anope::Init(ac, av);
|
|
}
|
|
catch (const CoreException &ex)
|
|
{
|
|
Log() << ex.GetReason();
|
|
return -1;
|
|
}
|
|
|
|
try
|
|
{
|
|
Uplink::Connect();
|
|
}
|
|
catch (const SocketException &ex)
|
|
{
|
|
Log(LOG_TERMINAL) << "Unable to connect to uplink #" << Anope::CurrentUplink << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << "): " << ex.GetReason();
|
|
}
|
|
|
|
/* Set up timers */
|
|
time_t last_check = Anope::CurTime;
|
|
UpdateTimer updateTimer(Config->UpdateTimeout);
|
|
|
|
/*** Main loop. ***/
|
|
while (!Anope::Quitting)
|
|
{
|
|
Log(LOG_DEBUG_2) << "Top of main loop";
|
|
|
|
/* Process timers */
|
|
if (Anope::CurTime - last_check >= Config->TimeoutCheck)
|
|
{
|
|
TimerManager::TickTimers(Anope::CurTime);
|
|
last_check = Anope::CurTime;
|
|
}
|
|
|
|
/* Process the socket engine */
|
|
SocketEngine::Process();
|
|
}
|
|
|
|
if (Anope::Restarting)
|
|
{
|
|
FOREACH_MOD(I_OnRestart, OnRestart());
|
|
}
|
|
else
|
|
{
|
|
FOREACH_MOD(I_OnShutdown, OnShutdown());
|
|
}
|
|
|
|
if (Anope::QuitReason.empty())
|
|
Anope::QuitReason = "Terminating, reason unknown";
|
|
Log() << Anope::QuitReason;
|
|
|
|
delete UplinkSock;
|
|
|
|
ModuleManager::UnloadAll();
|
|
SocketEngine::Shutdown();
|
|
for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
|
|
ModuleManager::UnloadModule(m, NULL);
|
|
|
|
ModuleManager::CleanupRuntimeDirectory();
|
|
|
|
#ifdef _WIN32
|
|
OnShutdown();
|
|
#endif
|
|
|
|
if (Anope::Restarting)
|
|
{
|
|
chdir(BinaryDir.c_str());
|
|
Anope::string sbin = "./" + Anope::ServicesBin;
|
|
av[0] = const_cast<char *>(sbin.c_str());
|
|
execve(Anope::ServicesBin.c_str(), av, envp);
|
|
Log() << "Restart failed";
|
|
Anope::ReturnValue = -1;
|
|
}
|
|
|
|
return Anope::ReturnValue;
|
|
}
|