Add simple Linux, Win32 daemons

This commit is contained in:
chertov 2014-04-20 05:54:34 +04:00
parent e6e11590c8
commit 0b210ee99d
7 changed files with 315 additions and 183 deletions

83
Daemon.cpp Normal file
View File

@ -0,0 +1,83 @@
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS // to use freopen
#endif
#include "Daemon.h"
#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 "Garlic.h"
#include "util.h"
#include "Streaming.h"
namespace i2p
{
namespace util
{
bool Daemon_Singleton::start()
{
isDaemon = i2p::util::config::GetArg("-daemon", 0);
isLogging = i2p::util::config::GetArg("-log", 0);
//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));
if (isLogging == 1)
{
std::string logfile = i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
logfile.append("/debug.log");
#else
logfile.append("\\debug.log");
#endif
freopen(logfile.c_str(), "a", stdout);
LogPrint("Logging to file enabled.");
}
httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
httpServer->Start();
i2p::data::netdb.Start();
i2p::transports.Start();
i2p::tunnel::tunnels.Start();
i2p::garlic::routing.Start();
i2p::stream::StartStreaming();
httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446));
httpProxy->Start();
return true;
}
bool Daemon_Singleton::stop()
{
LogPrint("Shutdown started.");
httpProxy->Stop();
i2p::stream::StopStreaming();
i2p::garlic::routing.Stop();
i2p::tunnel::tunnels.Stop();
i2p::transports.Stop();
i2p::data::netdb.Stop();
httpServer->Stop();
delete httpProxy; httpProxy = NULL;
delete httpServer; httpServer = NULL;
if (isLogging == 1)
{
fclose(stdout);
}
return true;
}
}
}

63
Daemon.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
#include "HTTPServer.h"
#include "HTTPProxy.h"
namespace i2p
{
namespace util
{
class Daemon_Singleton
{
public:
virtual bool start();
virtual bool stop();
int isLogging;
int isDaemon;
int running = 1;
private:
i2p::util::HTTPServer *httpServer;
i2p::proxy::HTTPProxy *httpProxy;
protected:
Daemon_Singleton() : running(1) {};
virtual ~Daemon_Singleton() {
delete httpServer;
delete httpProxy;
};
};
#ifdef _WIN32
#define Daemon i2p::util::DaemonWin32::Instance()
class DaemonWin32 : public Daemon_Singleton
{
public:
static DaemonWin32& Instance()
{
static DaemonWin32 instance;
return instance;
}
virtual bool start();
virtual bool stop();
};
#else
#define Daemon i2p::util::DaemonLinux::Instance()
class DaemonLinux : public Daemon_Singleton
{
public:
static DaemonLinux& Instance()
{
static DaemonLinux instance;
return instance;
}
virtual bool start();
virtual bool stop();
};
#endif
}
}

109
DaemonLinux.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "Daemon.h"
#ifndef _WIN32
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
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;
}
}
namespace i2p
{
namespace util
{
bool DaemonLinux::start()
{
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);
retunrn Daemon_Singleton::start();
}
bool DaemonLinux::stop()
{
Daemon_Singleton::stop();
close(pidFilehandle);
unlink(pidfile.c_str());
return true;
}
}
}
#endif

31
DaemonWin32.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "Daemon.h"
#ifdef _WIN32
#include "./Win32/Win32Service.h"
namespace i2p
{
namespace util
{
bool DaemonWin32::start()
{
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
service_control(isDaemon);
return Daemon_Singleton::start();
}
bool DaemonWin32::stop()
{
return Daemon_Singleton::stop();
}
}
}
#endif

View File

@ -13,6 +13,9 @@
<ItemGroup>
<ClCompile Include="..\AddressBook.cpp" />
<ClCompile Include="..\base64.cpp" />
<ClCompile Include="..\Daemon.cpp" />
<ClCompile Include="..\DaemonLinux.cpp" />
<ClCompile Include="..\DaemonWin32.cpp" />
<ClCompile Include="..\Garlic.cpp" />
<ClCompile Include="..\HTTPProxy.cpp" />
<ClCompile Include="..\HTTPServer.cpp" />
@ -43,6 +46,7 @@
<ClInclude Include="..\AddressBook.h" />
<ClInclude Include="..\base64.h" />
<ClInclude Include="..\CryptoConst.h" />
<ClInclude Include="..\Daemon.h" />
<ClInclude Include="..\ElGamal.h" />
<ClInclude Include="..\Garlic.h" />
<ClInclude Include="..\HTTPProxy.h" />

View File

@ -99,6 +99,15 @@
<ClCompile Include="Win32Service.cpp">
<Filter>Win32</Filter>
</ClCompile>
<ClCompile Include="..\Daemon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\DaemonLinux.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\DaemonWin32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Identity.h">
@ -200,5 +209,8 @@
<ClInclude Include="Win32Service.h">
<Filter>Win32</Filter>
</ClInclude>
<ClInclude Include="..\Daemon.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

196
i2p.cpp
View File

@ -1,193 +1,23 @@
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS // to use freopen
#endif
#include <iostream>
#include <thread>
#include <cryptopp/integer.h>
#include <boost/filesystem.hpp>
#ifndef _WIN32
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#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 "HTTPProxy.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
// Global
volatile int running = 1;
volatile 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
#include "Daemon.h"
int main( int argc, char* argv[] )
{
i2p::util::config::OptionParser(argc,argv);
volatile int isDaemon = i2p::util::config::GetArg("-daemon", 0);
#ifdef _WIN32
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
#endif
i2p::util::config::OptionParser(argc, argv);
#ifdef _WIN32
service_control(isDaemon);
#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);
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);
Daemon.start();
while (Daemon.running)
{
//TODO Meeh: Find something better to do here.
std::this_thread::sleep_for (std::chrono::seconds(1));
}
Daemon.start();
volatile 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
freopen(logfile.c_str(),"a",stdout);
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 ();
i2p::garlic::routing.Start ();
i2p::stream::StartStreaming ();
i2p::proxy::HTTPProxy httpProxy (i2p::util::config::GetArg("-httpproxyport", 4446));
httpProxy.Start();
while (running)
{
//TODO Meeh: Find something better to do here.
std::this_thread::sleep_for (std::chrono::seconds(1));
}
LogPrint("Shutdown started.");
httpProxy.Stop ();
i2p::stream::StopStreaming ();
i2p::garlic::routing.Stop ();
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;
return 0;
}