#ifdef _WIN32 #define _CRT_SECURE_NO_WARNINGS // to use freopen #endif #include #include #include #include #ifndef _WIN32 #include #include #include #else #include "./Win32/Win32Service.h" #endif #include "Log.h" #include "base64.h" #include "Transports.h" #include "NTCPSession.h" #include "RouterInfo.h" #include "RouterContext.h" #include "Tunnel.h" #include "NetDb.h" #include "HTTPServer.h" #include "util.h" #ifdef _WIN32 // Internal name of the service #define SERVICE_NAME "i2pService" // Displayed name of the service #define SERVICE_DISPLAY_NAME "i2p router service" // Service start options. #define SERVICE_START_TYPE SERVICE_DEMAND_START // List of service dependencies - "dep1\0dep2\0\0" #define SERVICE_DEPENDENCIES "" // The name of the account under which the service should run #define SERVICE_ACCOUNT "NT AUTHORITY\\LocalService" // The password to the service account name #define SERVICE_PASSWORD NULL #endif // Global int running = 1; int isDaemon; #ifndef _WIN32 void handle_signal(int sig) { switch (sig) { case SIGHUP: if (i2p::util::config::GetArg("daemon", 0) == 1) { static bool first=true; if (first) { first=false; return; } } LogPrint("Reloading config."); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); break; case SIGABRT: case SIGTERM: case SIGINT: running = 0; // Exit loop break; } } #endif int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); isDaemon = i2p::util::config::GetArg("-daemon", 0); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); SetConsoleOutputCP(1251); setlocale(LC_ALL, "Russian"); #endif LogPrint("\n\n\n\ni2pd starting\n"); LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); #ifdef _WIN32 std::string serviceControl = i2p::util::config::GetArg("-service", "none"); if (serviceControl == "install") { InstallService( SERVICE_NAME, // Name of service SERVICE_DISPLAY_NAME, // Name to display SERVICE_START_TYPE, // Service start type SERVICE_DEPENDENCIES, // Dependencies SERVICE_ACCOUNT, // Service running account SERVICE_PASSWORD // Password of the account ); return 0; } else if (serviceControl == "remove") { UninstallService(SERVICE_NAME); return 0; } else if (serviceControl != "none") { printf(" --service=install to install the service.\n"); printf(" --service=remove to remove the service.\n"); return 0; } else if (isDaemon) { std::string logfile = i2p::util::filesystem::GetDataDir().string(); logfile.append("\\debug.log"); FILE* openResult = freopen(logfile.c_str(), "a", stdout); if (!openResult) { return -17; } LogPrint("Service logging enabled."); I2PService service(SERVICE_NAME); if (!I2PService::Run(service)) { LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError()); } return 0; } #endif int isLogging = i2p::util::config::GetArg("-log", 0); if (isLogging == 1) { std::string logfile = i2p::util::filesystem::GetDataDir().string(); #ifndef _WIN32 logfile.append("/debug.log"); #else logfile.append("\\debug.log"); #endif FILE* openResult = freopen(logfile.c_str(),"a",stdout); // It seems that we need to add FLUSH() for LogPrint and call it in some important places if (!openResult) { LogPrint("Can't do [freopen()]."); return -17; } LogPrint("Logging to file enabled."); } #ifndef _WIN32 if (isDaemon == 1) { pid_t pid; pid = fork(); if (pid > 0) { g_Log.Stop(); return 0; } if (pid < 0) { return -1; } umask(0); int sid = setsid(); if (sid < 0) { LogPrint("Error, could not create process group."); return -1; } chdir(i2p::util::filesystem::GetDataDir().string().c_str()); } // Pidfile std::string pidfile = i2p::util::filesystem::GetDataDir().string(); pidfile.append("/i2pd.pid"); int pidFilehandle = open(pidfile.c_str(), O_RDWR|O_CREAT, 0600); if (pidFilehandle == -1 ) { LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?"); return -1; } if (lockf(pidFilehandle,F_TLOCK,0) == -1) { LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?"); return -1; } char pid[10]; sprintf(pid,"%d\n",getpid()); write(pidFilehandle, pid, strlen(pid)); // Signal handler struct sigaction sa; sa.sa_handler = handle_signal; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGHUP,&sa,0); sigaction(SIGABRT,&sa,0); sigaction(SIGTERM,&sa,0); sigaction(SIGINT,&sa,0); #endif //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), i2p::util::config::GetArg("-port", 17070)); i2p::util::HTTPServer httpServer (i2p::util::config::GetArg("-httpport", 7070)); httpServer.Start (); i2p::data::netdb.Start (); i2p::transports.Start (); i2p::tunnel::tunnels.Start (); while (running) { //TODO Meeh: Find something better to do here. std::this_thread::sleep_for (std::chrono::seconds(1)); } LogPrint("Shutdown started."); i2p::tunnel::tunnels.Stop (); i2p::transports.Stop (); i2p::data::netdb.Stop (); httpServer.Stop (); if (isLogging == 1) { fclose (stdout); } #ifndef _WIN32 close(pidFilehandle); unlink(pidfile.c_str()); #endif return 0; }