anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

main.cpp (5295B)

      1 /* Services -- main source file.
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "timers.h"
     14 #include "config.h"
     15 #include "bots.h"
     16 #include "socketengine.h"
     17 #include "uplink.h"
     18 
     19 #ifndef _WIN32
     20 #include <limits.h>
     21 #else
     22 #include <process.h>
     23 #endif
     24 
     25 /* Command-line options: */
     26 int Anope::Debug = 0;
     27 bool Anope::ReadOnly = false, Anope::NoFork = false, Anope::NoThird = false, Anope::NoExpire = false, Anope::ProtocolDebug = false;
     28 Anope::string Anope::ServicesDir;
     29 Anope::string Anope::ServicesBin;
     30 
     31 int Anope::ReturnValue = 0;
     32 sig_atomic_t Anope::Signal = 0;
     33 bool Anope::Quitting = false;
     34 bool Anope::Restarting = false;
     35 Anope::string Anope::QuitReason;
     36 
     37 static Anope::string BinaryDir;       /* Full path to services bin directory */
     38 
     39 time_t Anope::StartTime = time(NULL);
     40 time_t Anope::CurTime = time(NULL);
     41 
     42 int Anope::CurrentUplink = -1;
     43 
     44 class UpdateTimer : public Timer
     45 {
     46  public:
     47 	UpdateTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
     48 
     49 	void Tick(time_t) anope_override
     50 	{
     51 		Anope::SaveDatabases();
     52 	}
     53 };
     54 
     55 class ExpireTimer : public Timer
     56 {
     57  public:
     58 	ExpireTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
     59 
     60 	void Tick(time_t) anope_override
     61 	{
     62 		FOREACH_MOD(OnExpireTick, ());
     63 	}
     64 };
     65 
     66 void Anope::SaveDatabases()
     67 {
     68 	if (Anope::ReadOnly)
     69 		return;
     70 
     71 	Log(LOG_DEBUG) << "Saving databases";
     72 	FOREACH_MOD(OnSaveDatabase, ());
     73 }
     74 
     75 /** The following comes from InspIRCd to get the full path of the Anope executable
     76  */
     77 static Anope::string GetFullProgDir(const Anope::string &argv0)
     78 {
     79 	char buffer[PATH_MAX];
     80 #ifdef _WIN32
     81 	/* Windows has specific API calls to get the EXE path that never fail.
     82 	 * For once, Windows has something of use, compared to the POSIX code
     83 	 * for this, this is positively neato.
     84 	 */
     85 	if (GetModuleFileName(NULL, buffer, PATH_MAX))
     86 	{
     87 		Anope::string fullpath = buffer;
     88 		Anope::string::size_type n = fullpath.rfind("\\");
     89 		Anope::ServicesBin = fullpath.substr(n + 1, fullpath.length());
     90 		return fullpath.substr(0, n);
     91 	}
     92 #else
     93 	// Get the current working directory
     94 	if (getcwd(buffer, PATH_MAX))
     95 	{
     96 		Anope::string remainder = argv0;
     97 
     98 		Anope::ServicesBin = remainder;
     99 		Anope::string::size_type n = Anope::ServicesBin.rfind("/");
    100 		Anope::string fullpath;
    101 		if (Anope::ServicesBin[0] == '/')
    102 			fullpath = Anope::ServicesBin.substr(0, n);
    103 		else
    104 			fullpath = Anope::string(buffer) + "/" + Anope::ServicesBin.substr(0, n);
    105 		Anope::ServicesBin = Anope::ServicesBin.substr(n + 1, remainder.length());
    106 		return fullpath;
    107 	}
    108 #endif
    109 	return "/";
    110 }
    111 
    112 /* Main routine.  (What does it look like? :-) ) */
    113 
    114 int main(int ac, char **av, char **envp)
    115 {
    116 	/* String comparisons won't work until we build the case map cache, so do it first */
    117 	Anope::CaseMapRebuild();
    118 
    119 	BinaryDir = GetFullProgDir(av[0]);
    120 	if (BinaryDir[BinaryDir.length() - 1] == '.')
    121 		BinaryDir = BinaryDir.substr(0, BinaryDir.length() - 2);
    122 
    123 #ifdef _WIN32
    124 	Anope::string::size_type n = BinaryDir.rfind('\\');
    125 #else
    126 	Anope::string::size_type n = BinaryDir.rfind('/');
    127 #endif
    128 	Anope::ServicesDir = BinaryDir.substr(0, n);
    129 
    130 #ifdef _WIN32
    131 	/* Clean out the module runtime directory prior to running, just in case files were left behind during a previous run */
    132 	ModuleManager::CleanupRuntimeDirectory();
    133 
    134 	OnStartup();
    135 #endif
    136 
    137 	try
    138 	{
    139 		/* General initialization first */
    140 		Anope::Init(ac, av);
    141 	}
    142 	catch (const CoreException &ex)
    143 	{
    144 		Log() << ex.GetReason();
    145 		return -1;
    146 	}
    147 
    148 	try
    149 	{
    150 		Uplink::Connect();
    151 	}
    152 	catch (const SocketException &ex)
    153 	{
    154 		Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason();
    155 	}
    156 
    157 	/* Set up timers */
    158 	time_t last_check = Anope::CurTime;
    159 	UpdateTimer updateTimer(Config->GetBlock("options")->Get<time_t>("updatetimeout", "5m"));
    160 	ExpireTimer expireTimer(Config->GetBlock("options")->Get<time_t>("expiretimeout", "30m"));
    161 
    162 	/*** Main loop. ***/
    163 	while (!Anope::Quitting)
    164 	{
    165 		Log(LOG_DEBUG_2) << "Top of main loop";
    166 
    167 		/* Process timers */
    168 		if (Anope::CurTime - last_check >= Config->TimeoutCheck)
    169 		{
    170 			TimerManager::TickTimers(Anope::CurTime);
    171 			last_check = Anope::CurTime;
    172 		}
    173 
    174 		/* Process the socket engine */
    175 		SocketEngine::Process();
    176 
    177 		if (Anope::Signal)
    178 			Anope::HandleSignal();
    179 	}
    180 
    181 	if (Anope::Restarting)
    182 	{
    183 		FOREACH_MOD(OnRestart, ());
    184 	}
    185 	else
    186 	{
    187 		FOREACH_MOD(OnShutdown, ());
    188 	}
    189 
    190 	if (Anope::QuitReason.empty())
    191 		Anope::QuitReason = "Terminating, reason unknown";
    192 	Log() << Anope::QuitReason;
    193 
    194 	delete UplinkSock;
    195 
    196 	ModuleManager::UnloadAll();
    197 	SocketEngine::Shutdown();
    198 	for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
    199 		ModuleManager::UnloadModule(m, NULL);
    200 
    201 #ifdef _WIN32
    202 	ModuleManager::CleanupRuntimeDirectory();
    203 
    204 	OnShutdown();
    205 #endif
    206 
    207 	if (Anope::Restarting)
    208 	{
    209 		chdir(BinaryDir.c_str());
    210 		Anope::string sbin = "./" + Anope::ServicesBin;
    211 		av[0] = const_cast<char *>(sbin.c_str());
    212 		execve(Anope::ServicesBin.c_str(), av, envp);
    213 		Log() << "Restart failed";
    214 		Anope::ReturnValue = -1;
    215 	}
    216 
    217 	return Anope::ReturnValue;
    218 }