main.cpp

Go to the documentation of this file.
00001 /* Services -- main source file.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  */
00012 
00013 #include "services.h"
00014 #include "timers.h"
00015 #include "config.h"
00016 #include "bots.h"
00017 #include "socketengine.h"
00018 #include "uplink.h"
00019 
00020 #ifndef _WIN32
00021 #include <limits.h>
00022 #else
00023 #include <process.h>
00024 #endif
00025 
00026 /* Command-line options: */
00027 int Anope::Debug = 0;
00028 bool Anope::ReadOnly = false, Anope::NoFork = false, Anope::NoThird = false, Anope::NoExpire = false, Anope::ProtocolDebug = false;
00029 Anope::string Anope::ServicesDir;
00030 Anope::string Anope::ServicesBin;
00031 
00032 int Anope::ReturnValue = 0;
00033 sig_atomic_t Anope::Signal = 0;
00034 bool Anope::Quitting = false;
00035 bool Anope::Restarting = false;
00036 Anope::string Anope::QuitReason;
00037 
00038 static Anope::string BinaryDir;       /* Full path to services bin directory */
00039 
00040 time_t Anope::StartTime = time(NULL);
00041 time_t Anope::CurTime = time(NULL);
00042 
00043 int Anope::CurrentUplink = -1;
00044 
00045 class UpdateTimer : public Timer
00046 {
00047  public:
00048         UpdateTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
00049 
00050         void Tick(time_t)
00051         {
00052                 Anope::SaveDatabases();
00053         }
00054 };
00055 
00056 void Anope::SaveDatabases()
00057 {
00058         if (Anope::ReadOnly)
00059                 return;
00060 
00061         EventReturn MOD_RESULT;
00062         FOREACH_RESULT(I_OnSaveDatabase, OnSaveDatabase());
00063         Log(LOG_DEBUG) << "Saving databases";
00064 }
00065 
00068 static Anope::string GetFullProgDir(const Anope::string &argv0)
00069 {
00070         char buffer[PATH_MAX];
00071 #ifdef _WIN32
00072         /* Windows has specific API calls to get the EXE path that never fail.
00073          * For once, Windows has something of use, compared to the POSIX code
00074          * for this, this is positively neato.
00075          */
00076         if (GetModuleFileName(NULL, buffer, PATH_MAX))
00077         {
00078                 Anope::string fullpath = buffer;
00079                 Anope::string::size_type n = fullpath.rfind("\\");
00080                 Anope::ServicesBin = fullpath.substr(n + 1, fullpath.length());
00081                 return fullpath.substr(0, n);
00082         }
00083 #else
00084         // Get the current working directory
00085         if (getcwd(buffer, PATH_MAX))
00086         {
00087                 Anope::string remainder = argv0;
00088 
00089                 Anope::ServicesBin = remainder;
00090                 Anope::string::size_type n = Anope::ServicesBin.rfind("/");
00091                 Anope::string fullpath;
00092                 if (Anope::ServicesBin[0] == '/')
00093                         fullpath = Anope::ServicesBin.substr(0, n);
00094                 else
00095                         fullpath = Anope::string(buffer) + "/" + Anope::ServicesBin.substr(0, n);
00096                 Anope::ServicesBin = Anope::ServicesBin.substr(n + 1, remainder.length());
00097                 return fullpath;
00098         }
00099 #endif
00100         return "/";
00101 }
00102 
00103 /*************************************************************************/
00104 
00105 /* Main routine.  (What does it look like? :-) ) */
00106 
00107 int main(int ac, char **av, char **envp)
00108 {
00109         BinaryDir = GetFullProgDir(av[0]);
00110         if (BinaryDir[BinaryDir.length() - 1] == '.')
00111                 BinaryDir = BinaryDir.substr(0, BinaryDir.length() - 2);
00112 
00113 #ifdef _WIN32
00114         Anope::string::size_type n = BinaryDir.rfind('\\');
00115 #else
00116         Anope::string::size_type n = BinaryDir.rfind('/');
00117 #endif
00118         Anope::ServicesDir = BinaryDir.substr(0, n);
00119 
00120         /* Clean out the module runtime directory prior to running, just in case files were left behind during a previous run */
00121         ModuleManager::CleanupRuntimeDirectory();
00122 
00123 #ifdef _WIN32
00124         OnStartup();
00125 #endif
00126 
00127         try
00128         {
00129                 /* General initialization first */
00130                 Anope::Init(ac, av);
00131         }
00132         catch (const CoreException &ex)
00133         {
00134                 Log() << ex.GetReason();
00135                 return -1;
00136         }
00137 
00138         try
00139         {
00140                 Uplink::Connect();
00141         }
00142         catch (const SocketException &ex)
00143         {
00144                 Log(LOG_TERMINAL) << "Unable to connect to uplink #" << Anope::CurrentUplink << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << "): " << ex.GetReason();
00145         }
00146 
00147         /* Set up timers */
00148         time_t last_check = Anope::CurTime;
00149         UpdateTimer updateTimer(Config->UpdateTimeout);
00150 
00151         /*** Main loop. ***/
00152         while (!Anope::Quitting)
00153         {
00154                 Log(LOG_DEBUG_2) << "Top of main loop";
00155 
00156                 /* Process timers */
00157                 if (Anope::CurTime - last_check >= Config->TimeoutCheck)
00158                 {
00159                         TimerManager::TickTimers(Anope::CurTime);
00160                         last_check = Anope::CurTime;
00161                 }
00162 
00163                 /* Process the socket engine */
00164                 SocketEngine::Process();
00165 
00166                 if (Anope::Signal)
00167                         Anope::HandleSignal();
00168         }
00169 
00170         if (Anope::Restarting)
00171         {
00172                 FOREACH_MOD(I_OnRestart, OnRestart());
00173         }
00174         else
00175         {
00176                 FOREACH_MOD(I_OnShutdown, OnShutdown());
00177         }
00178 
00179         if (Anope::QuitReason.empty())
00180                 Anope::QuitReason = "Terminating, reason unknown";
00181         Log() << Anope::QuitReason;
00182 
00183         delete UplinkSock;
00184 
00185         ModuleManager::UnloadAll();
00186         SocketEngine::Shutdown();
00187         for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
00188                 ModuleManager::UnloadModule(m, NULL);
00189 
00190         ModuleManager::CleanupRuntimeDirectory();
00191 
00192 #ifdef _WIN32
00193         OnShutdown();
00194 #endif
00195 
00196         if (Anope::Restarting)
00197         {
00198                 chdir(BinaryDir.c_str());
00199                 Anope::string sbin = "./" + Anope::ServicesBin;
00200                 av[0] = const_cast<char *>(sbin.c_str());
00201                 execve(Anope::ServicesBin.c_str(), av, envp);
00202                 Log() << "Restart failed";
00203                 Anope::ReturnValue = -1;
00204         }
00205 
00206         return Anope::ReturnValue;
00207 }