i2pd/daemon/UnixDaemon.cpp

231 lines
6.3 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2014-04-20 01:54:34 +00:00
#include "Daemon.h"
#ifndef _WIN32
#include <signal.h>
#include <stdlib.h>
2016-03-08 20:02:32 +00:00
#include <thread>
2014-04-20 01:54:34 +00:00
#include <unistd.h>
2014-04-22 22:37:24 +00:00
#include <fcntl.h>
#include <sys/stat.h>
2016-11-04 00:00:00 +00:00
#include <sys/resource.h>
2014-04-20 01:54:34 +00:00
2016-01-20 00:00:00 +00:00
#include "Config.h"
#include "FS.h"
2014-04-22 22:37:24 +00:00
#include "Log.h"
#include "Tunnel.h"
2016-03-29 16:50:34 +00:00
#include "RouterContext.h"
#include "ClientContext.h"
#include "Transports.h"
2014-04-22 04:15:07 +00:00
2014-04-20 01:54:34 +00:00
void handle_signal(int sig)
{
switch (sig)
{
2016-03-29 16:34:53 +00:00
case SIGHUP:
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration...");
i2p::client::context.ReloadConfig();
2016-03-29 16:34:53 +00:00
break;
case SIGUSR1:
LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs...");
i2p::log::Logger().Reopen ();
break;
2016-03-29 16:34:53 +00:00
case SIGINT:
2016-10-31 10:27:27 +00:00
if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval)
{
2016-03-30 01:37:30 +00:00
i2p::context.SetAcceptsTunnels (false);
2016-10-31 10:27:27 +00:00
Daemon.gracefulShutdownInterval = 10*60; // 10 minutes
LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds");
}
2016-03-30 01:37:30 +00:00
else
Daemon.running = 0;
break;
2016-03-29 16:34:53 +00:00
case SIGABRT:
case SIGTERM:
Daemon.running = 0; // Exit loop
2014-04-20 01:54:34 +00:00
break;
2017-03-20 13:52:43 +00:00
case SIGPIPE:
LogPrint(eLogInfo, "SIGPIPE received");
break;
case SIGTSTP:
LogPrint(eLogInfo, "Daemon: Got SIGTSTP, disconnecting from network...");
i2p::transport::transports.SetOnline(false);
break;
case SIGCONT:
LogPrint(eLogInfo, "Daemon: Got SIGCONT, restoring connection to network...");
i2p::transport::transports.SetOnline(true);
break;
}
2014-04-20 01:54:34 +00:00
}
namespace i2p
{
namespace util
{
bool DaemonLinux::start()
{
2016-06-01 00:00:00 +00:00
if (isDaemon)
2014-04-20 01:54:34 +00:00
{
pid_t pid;
pid = fork();
2014-07-02 17:48:45 +00:00
if (pid > 0) // parent
::exit (EXIT_SUCCESS);
2014-04-20 01:54:34 +00:00
2014-07-02 17:48:45 +00:00
if (pid < 0) // error
2016-01-11 10:55:18 +00:00
{
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Could not fork: ", strerror(errno));
std::cerr << "i2pd: Could not fork: " << strerror(errno) << std::endl;
2014-07-02 17:48:45 +00:00
return false;
2016-01-11 10:55:18 +00:00
}
2014-07-02 17:48:45 +00:00
// child
umask(S_IWGRP | S_IRWXO); // 0027
2014-04-20 01:54:34 +00:00
int sid = setsid();
if (sid < 0)
{
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Could not create process group.");
std::cerr << "i2pd: Could not create process group." << std::endl;
2014-07-02 17:48:45 +00:00
return false;
2014-04-20 01:54:34 +00:00
}
std::string d = i2p::fs::GetDataDir();
2016-01-11 11:30:19 +00:00
if (chdir(d.c_str()) != 0)
{
LogPrint(eLogError, "Daemon: Could not chdir: ", strerror(errno));
std::cerr << "i2pd: Could not chdir: " << strerror(errno) << std::endl;
2016-01-11 11:30:19 +00:00
return false;
}
2014-07-02 17:48:45 +00:00
2016-06-01 00:00:00 +00:00
// point std{in,out,err} descriptors to /dev/null
freopen("/dev/null", "r", stdin);
2016-12-22 15:52:26 +00:00
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
2014-04-20 01:54:34 +00:00
}
2016-11-04 00:00:00 +00:00
// set proc limits
struct rlimit limit;
uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles);
getrlimit(RLIMIT_NOFILE, &limit);
if (nfiles == 0) {
LogPrint(eLogInfo, "Daemon: Using system limit in ", limit.rlim_cur, " max open files");
2016-11-04 00:00:00 +00:00
} else if (nfiles <= limit.rlim_max) {
limit.rlim_cur = nfiles;
if (setrlimit(RLIMIT_NOFILE, &limit) == 0) {
LogPrint(eLogInfo, "Daemon: Set max number of open files to ",
2016-11-04 00:00:00 +00:00
nfiles, " (system limit is ", limit.rlim_max, ")");
} else {
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Can't set max number of open files: ", strerror(errno));
2016-11-04 00:00:00 +00:00
}
} else {
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max);
2016-11-04 00:00:00 +00:00
}
uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize);
if (cfsize) // core file size set
{
cfsize *= 1024;
getrlimit(RLIMIT_CORE, &limit);
if (cfsize <= limit.rlim_max) {
limit.rlim_cur = cfsize;
if (setrlimit(RLIMIT_CORE, &limit) != 0) {
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Can't set max size of coredump: ", strerror(errno));
} else if (cfsize == 0) {
LogPrint(eLogInfo, "Daemon: coredumps disabled");
} else {
LogPrint(eLogInfo, "Daemon: Set max size of core files to ", cfsize / 1024, "Kb");
}
2016-11-04 00:00:00 +00:00
} else {
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max);
2016-11-04 00:00:00 +00:00
}
}
2016-11-04 00:00:00 +00:00
2014-04-20 01:54:34 +00:00
// Pidfile
2016-01-11 10:58:39 +00:00
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
2016-01-20 00:00:00 +00:00
std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
if (pidfile == "") {
pidfile = i2p::fs::DataDirPath("i2pd.pid");
}
2016-01-11 10:58:39 +00:00
if (pidfile != "") {
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
if (pidFH < 0)
{
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Could not create pid file ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not create pid file " << pidfile << ": " << strerror(errno) << std::endl;
2016-01-11 10:58:39 +00:00
return false;
}
#ifndef ANDROID
2016-01-11 10:58:39 +00:00
if (lockf(pidFH, F_TLOCK, 0) != 0)
{
2023-03-31 12:16:32 +00:00
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
2016-01-11 10:58:39 +00:00
return false;
}
#endif
2016-01-11 10:58:39 +00:00
char pid[10];
sprintf(pid, "%d\n", getpid());
ftruncate(pidFH, 0);
2016-01-11 11:30:19 +00:00
if (write(pidFH, pid, strlen(pid)) < 0)
{
2023-03-31 11:29:04 +00:00
LogPrint(eLogCritical, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
2016-01-11 11:30:19 +00:00
return false;
}
2014-04-20 01:54:34 +00:00
}
2016-10-31 10:27:27 +00:00
gracefulShutdownInterval = 0; // not specified
2014-04-20 01:54:34 +00:00
// handle signal TSTP
bool handleTSTP; i2p::config::GetOption("unix.handle_sigtstp", handleTSTP);
// Signal handler
struct sigaction sa;
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGHUP, &sa, 0);
sigaction(SIGUSR1, &sa, 0);
sigaction(SIGABRT, &sa, 0);
sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0);
sigaction(SIGPIPE, &sa, 0);
if (handleTSTP)
{
sigaction(SIGTSTP, &sa, 0);
sigaction(SIGCONT, &sa, 0);
}
return Daemon_Singleton::start();
2014-04-20 01:54:34 +00:00
}
bool DaemonLinux::stop()
{
i2p::fs::Remove(pidfile);
return Daemon_Singleton::stop();
2014-04-20 01:54:34 +00:00
}
2016-03-08 20:02:32 +00:00
void DaemonLinux::run ()
{
while (running)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
2016-10-31 10:27:27 +00:00
if (gracefulShutdownInterval)
2016-03-29 16:34:53 +00:00
{
2016-10-31 10:27:27 +00:00
gracefulShutdownInterval--; // - 1 second
if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0)
{
2016-03-29 16:34:53 +00:00
LogPrint(eLogInfo, "Graceful shutdown");
return;
}
}
2016-03-08 20:02:32 +00:00
}
}
2014-04-20 01:54:34 +00:00
}
}
2014-04-22 04:15:07 +00:00
#endif