Servatrice: refactor signal handling and permit config reloading
This commit is contained in:
parent
9947af7be9
commit
6cf3db7e6b
12 changed files with 163 additions and 95 deletions
|
@ -58,10 +58,13 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool
|
|||
connect(updateServerMessageButton, SIGNAL(clicked()), this, SLOT(actUpdateServerMessage()));
|
||||
shutdownServerButton = new QPushButton;
|
||||
connect(shutdownServerButton, SIGNAL(clicked()), this, SLOT(actShutdownServer()));
|
||||
reloadConfigButton = new QPushButton;
|
||||
connect(reloadConfigButton, SIGNAL(clicked()), this, SLOT(actReloadConfig()));
|
||||
|
||||
QVBoxLayout *vbox = new QVBoxLayout;
|
||||
vbox->addWidget(updateServerMessageButton);
|
||||
vbox->addWidget(shutdownServerButton);
|
||||
vbox->addWidget(reloadConfigButton);
|
||||
vbox->addStretch();
|
||||
|
||||
adminGroupBox = new QGroupBox;
|
||||
|
@ -87,6 +90,7 @@ void TabAdmin::retranslateUi()
|
|||
{
|
||||
updateServerMessageButton->setText(tr("Update server &message"));
|
||||
shutdownServerButton->setText(tr("&Shut down server"));
|
||||
reloadConfigButton->setText(tr("&Reload configuration"));
|
||||
adminGroupBox->setTitle(tr("Server administration functions"));
|
||||
|
||||
unlockButton->setText(tr("&Unlock functions"));
|
||||
|
@ -110,6 +114,12 @@ void TabAdmin::actShutdownServer()
|
|||
}
|
||||
}
|
||||
|
||||
void TabAdmin::actReloadConfig()
|
||||
{
|
||||
Command_ReloadConfig cmd;
|
||||
client->sendCommand(client->prepareAdminCommand(cmd));
|
||||
}
|
||||
|
||||
void TabAdmin::actUnlock()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Unlock administration functions"), tr("Do you really want to unlock the administration functions?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
|
|
@ -28,7 +28,7 @@ private:
|
|||
bool locked;
|
||||
AbstractClient *client;
|
||||
bool fullAdmin;
|
||||
QPushButton *updateServerMessageButton, *shutdownServerButton;
|
||||
QPushButton *updateServerMessageButton, *shutdownServerButton, *reloadConfigButton;
|
||||
QGroupBox *adminGroupBox;
|
||||
QPushButton *unlockButton, *lockButton;
|
||||
signals:
|
||||
|
@ -36,6 +36,7 @@ signals:
|
|||
private slots:
|
||||
void actUpdateServerMessage();
|
||||
void actShutdownServer();
|
||||
void actReloadConfig();
|
||||
|
||||
void actUnlock();
|
||||
void actLock();
|
||||
|
|
|
@ -2,6 +2,7 @@ message AdminCommand {
|
|||
enum AdminCommandType {
|
||||
UPDATE_SERVER_MESSAGE = 1000;
|
||||
SHUTDOWN_SERVER = 1001;
|
||||
RELOAD_CONFIG = 1002;
|
||||
}
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
@ -19,3 +20,9 @@ message Command_ShutdownServer {
|
|||
optional string reason = 1;
|
||||
optional uint32 minutes = 2;
|
||||
}
|
||||
|
||||
message Command_ReloadConfig {
|
||||
extend AdminCommand {
|
||||
optional Command_ReloadConfig ext = 1002;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ SET(servatrice_SOURCES
|
|||
src/serversocketinterface.cpp
|
||||
src/settingscache.cpp
|
||||
src/isl_interface.cpp
|
||||
src/signalhandler.cpp
|
||||
${VERSION_STRING_CPP}
|
||||
src/smtp/emailaddress.cpp
|
||||
src/smtp/mimeattachment.cpp
|
||||
|
|
|
@ -28,21 +28,16 @@
|
|||
#include "servatrice.h"
|
||||
#include "server_logger.h"
|
||||
#include "settingscache.h"
|
||||
#include "signalhandler.h"
|
||||
#include "rng_sfmt.h"
|
||||
#include "version_string.h"
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define SIGSEGV_TRACE_LINES 40
|
||||
|
||||
RNG_Abstract *rng;
|
||||
ServerLogger *logger;
|
||||
QThread *loggerThread;
|
||||
SettingsCache *settingsCache;
|
||||
SignalHandler *signalhandler;
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
|
@ -55,9 +50,6 @@ void myMessageOutput2(QtMsgType type, const char *msg);
|
|||
void myMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg);
|
||||
void myMessageOutput2(QtMsgType type, const QMessageLogContext &, const QString &msg);
|
||||
#endif
|
||||
#ifdef Q_OS_UNIX
|
||||
void sigSegvHandler(int sig);
|
||||
#endif
|
||||
|
||||
/* Implementations */
|
||||
|
||||
|
@ -130,32 +122,6 @@ void myMessageOutput2(QtMsgType /*type*/, const QMessageLogContext &, const QStr
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
void sigSegvHandler(int sig)
|
||||
{
|
||||
void *array[SIGSEGV_TRACE_LINES];
|
||||
size_t size;
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, SIGSEGV_TRACE_LINES);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "Error: signal %d:\n", sig);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
|
||||
if (sig == SIGSEGV)
|
||||
logger->logMessage("CRASH: SIGSEGV");
|
||||
else if (sig == SIGABRT)
|
||||
logger->logMessage("CRASH: SIGABRT");
|
||||
|
||||
logger->deleteLater();
|
||||
loggerThread->wait();
|
||||
delete loggerThread;
|
||||
|
||||
raise(sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
@ -202,23 +168,8 @@ int main(int argc, char *argv[])
|
|||
qInstallMessageHandler(myMessageOutput2);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
struct sigaction hup;
|
||||
hup.sa_handler = ServerLogger::hupSignalHandler;
|
||||
sigemptyset(&hup.sa_mask);
|
||||
hup.sa_flags = 0;
|
||||
hup.sa_flags |= SA_RESTART;
|
||||
sigaction(SIGHUP, &hup, 0);
|
||||
signalhandler = new SignalHandler();
|
||||
|
||||
struct sigaction segv;
|
||||
segv.sa_handler = sigSegvHandler;
|
||||
segv.sa_flags = SA_RESETHAND;
|
||||
sigemptyset(&segv.sa_mask);
|
||||
sigaction(SIGSEGV, &segv, 0);
|
||||
sigaction(SIGABRT, &segv, 0);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
rng = new RNG_SFMT;
|
||||
|
||||
std::cerr << "Servatrice " << VERSION_STRING << " starting." << std::endl;
|
||||
|
@ -250,6 +201,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
delete rng;
|
||||
delete signalhandler;
|
||||
delete settingsCache;
|
||||
|
||||
logger->deleteLater();
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
#define MAIN_H
|
||||
|
||||
class ServerLogger;
|
||||
class QThread;
|
||||
class SettingsCache;
|
||||
|
||||
extern ServerLogger *logger;
|
||||
extern QThread *loggerThread;
|
||||
extern SettingsCache *settingsCache;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
#include "server_logger.h"
|
||||
#include "settingscache.h"
|
||||
#include <QSocketNotifier>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <iostream>
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
ServerLogger::ServerLogger(bool _logToConsole, QObject *parent)
|
||||
: QObject(parent), logToConsole(_logToConsole), flushRunning(false)
|
||||
|
@ -44,13 +38,6 @@ void ServerLogger::startLog(const QString &logFileName)
|
|||
logFile = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
::socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFD);
|
||||
|
||||
snHup = new QSocketNotifier(sigHupFD[1], QSocketNotifier::Read, this);
|
||||
connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
|
||||
#endif
|
||||
} else
|
||||
logFile = 0;
|
||||
|
||||
|
@ -119,35 +106,13 @@ void ServerLogger::flushBuffer()
|
|||
}
|
||||
}
|
||||
|
||||
void ServerLogger::hupSignalHandler(int /*unused*/)
|
||||
void ServerLogger::rotateLogs()
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
if (!logFile)
|
||||
return;
|
||||
|
||||
char a = 1;
|
||||
ssize_t writeValue = ::write(sigHupFD[0], &a, sizeof(a));
|
||||
Q_UNUSED(writeValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerLogger::handleSigHup()
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
if (!logFile)
|
||||
return;
|
||||
|
||||
snHup->setEnabled(false);
|
||||
char tmp;
|
||||
ssize_t readValue = ::read(sigHupFD[1], &tmp, sizeof(tmp));
|
||||
Q_UNUSED(readValue);
|
||||
|
||||
logFile->close();
|
||||
logFile->open(QIODevice::Append);
|
||||
|
||||
snHup->setEnabled(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
QFile *ServerLogger::logFile;
|
||||
int ServerLogger::sigHupFD[2];
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <QWaitCondition>
|
||||
#include <QStringList>
|
||||
|
||||
class QSocketNotifier;
|
||||
class QFile;
|
||||
class Server_ProtocolHandler;
|
||||
|
||||
|
@ -16,19 +15,16 @@ class ServerLogger : public QObject {
|
|||
public:
|
||||
ServerLogger(bool _logToConsole, QObject *parent = 0);
|
||||
~ServerLogger();
|
||||
static void hupSignalHandler(int unused);
|
||||
public slots:
|
||||
void startLog(const QString &logFileName);
|
||||
void logMessage(QString message, void *caller = 0);
|
||||
void rotateLogs();
|
||||
private slots:
|
||||
void handleSigHup();
|
||||
void flushBuffer();
|
||||
signals:
|
||||
void sigFlushBuffer();
|
||||
private:
|
||||
bool logToConsole;
|
||||
static int sigHupFD[2];
|
||||
QSocketNotifier *snHup;
|
||||
static QFile *logFile;
|
||||
bool flushRunning;
|
||||
QStringList buffer;
|
||||
|
|
|
@ -289,6 +289,7 @@ Response::ResponseCode ServerSocketInterface::processExtendedAdminCommand(int cm
|
|||
switch ((AdminCommand::AdminCommandType) cmdType) {
|
||||
case AdminCommand::SHUTDOWN_SERVER: return cmdShutdownServer(cmd.GetExtension(Command_ShutdownServer::ext), rc);
|
||||
case AdminCommand::UPDATE_SERVER_MESSAGE: return cmdUpdateServerMessage(cmd.GetExtension(Command_UpdateServerMessage::ext), rc);
|
||||
case AdminCommand::RELOAD_CONFIG: return cmdReloadConfig(cmd.GetExtension(Command_ReloadConfig::ext), rc);
|
||||
default: return Response::RespFunctionNotAllowed;
|
||||
}
|
||||
}
|
||||
|
@ -956,3 +957,9 @@ Response::ResponseCode ServerSocketInterface::cmdShutdownServer(const Command_Sh
|
|||
QMetaObject::invokeMethod(server, "scheduleShutdown", Q_ARG(QString, QString::fromStdString(cmd.reason())), Q_ARG(int, cmd.minutes()));
|
||||
return Response::RespOk;
|
||||
}
|
||||
|
||||
Response::ResponseCode ServerSocketInterface::cmdReloadConfig(const Command_ReloadConfig &cmd, ResponseContainer & /*rc*/)
|
||||
{
|
||||
settingsCache->sync();
|
||||
return Response::RespOk;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ class Command_ReplayDeleteMatch;
|
|||
class Command_BanFromServer;
|
||||
class Command_UpdateServerMessage;
|
||||
class Command_ShutdownServer;
|
||||
class Command_ReloadConfig;
|
||||
|
||||
class ServerSocketInterface : public Server_ProtocolHandler
|
||||
{
|
||||
|
@ -94,6 +95,7 @@ private:
|
|||
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdRegisterAccount(const Command_Register &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdActivateAccount(const Command_Activate &cmd, ResponseContainer & /* rc */);
|
||||
Response::ResponseCode cmdReloadConfig(const Command_ReloadConfig &cmd, ResponseContainer & /*rc*/);
|
||||
|
||||
Response::ResponseCode processExtendedSessionCommand(int cmdType, const SessionCommand &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode processExtendedModeratorCommand(int cmdType, const ModeratorCommand &cmd, ResponseContainer &rc);
|
||||
|
|
98
servatrice/src/signalhandler.cpp
Normal file
98
servatrice/src/signalhandler.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
#include <QSocketNotifier>
|
||||
|
||||
#include "signalhandler.h"
|
||||
#include "server_logger.h"
|
||||
#include "settingscache.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#define SIGSEGV_TRACE_LINES 40
|
||||
|
||||
int SignalHandler::sigHupFD[2];
|
||||
|
||||
SignalHandler::SignalHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
::socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFD);
|
||||
|
||||
snHup = new QSocketNotifier(sigHupFD[1], QSocketNotifier::Read, this);
|
||||
connect(snHup, SIGNAL(activated(int)), this, SLOT(internalSigHupHandler()));
|
||||
|
||||
struct sigaction hup;
|
||||
hup.sa_handler = SignalHandler::sigHupHandler;
|
||||
sigemptyset(&hup.sa_mask);
|
||||
hup.sa_flags = 0;
|
||||
hup.sa_flags |= SA_RESTART;
|
||||
sigaction(SIGHUP, &hup, 0);
|
||||
|
||||
struct sigaction segv;
|
||||
segv.sa_handler = SignalHandler::sigSegvHandler;
|
||||
segv.sa_flags = SA_RESETHAND;
|
||||
sigemptyset(&segv.sa_mask);
|
||||
sigaction(SIGSEGV, &segv, 0);
|
||||
sigaction(SIGABRT, &segv, 0);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SignalHandler::sigHupHandler(int /* sig */)
|
||||
{
|
||||
char a = 1;
|
||||
ssize_t writeValue = ::write(sigHupFD[0], &a, sizeof(a));
|
||||
Q_UNUSED(writeValue);
|
||||
}
|
||||
|
||||
void SignalHandler::internalSigHupHandler()
|
||||
{
|
||||
snHup->setEnabled(false);
|
||||
char tmp;
|
||||
ssize_t readValue = ::read(sigHupFD[1], &tmp, sizeof(tmp));
|
||||
Q_UNUSED(readValue);
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
std::cerr << "Received SIGHUP" << std::endl;
|
||||
#endif
|
||||
logger->logMessage("Received SIGHUP");
|
||||
logger->rotateLogs();
|
||||
|
||||
settingsCache->sync();
|
||||
|
||||
snHup->setEnabled(true);
|
||||
}
|
||||
|
||||
void SignalHandler::sigSegvHandler(int sig)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
void *array[SIGSEGV_TRACE_LINES];
|
||||
size_t size;
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, SIGSEGV_TRACE_LINES);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "Error: signal %d:\n", sig);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
#endif
|
||||
if (sig == SIGSEGV)
|
||||
logger->logMessage("CRASH: SIGSEGV");
|
||||
else if (sig == SIGABRT)
|
||||
logger->logMessage("CRASH: SIGABRT");
|
||||
|
||||
logger->deleteLater();
|
||||
loggerThread->wait();
|
||||
delete loggerThread;
|
||||
|
||||
raise(sig);
|
||||
}
|
||||
|
24
servatrice/src/signalhandler.h
Normal file
24
servatrice/src/signalhandler.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef SIGNALHANDLER_H
|
||||
#define SIGNALHANDLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QSocketNotifier;
|
||||
|
||||
class SignalHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SignalHandler(QObject *parent = 0);
|
||||
~SignalHandler() { };
|
||||
static void sigHupHandler(int /* sig */);
|
||||
static void sigSegvHandler(int sig);
|
||||
private:
|
||||
static int sigHupFD[2];
|
||||
QSocketNotifier *snHup;
|
||||
private slots:
|
||||
void internalSigHupHandler();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue