diff --git a/cockatrice/src/tab_admin.cpp b/cockatrice/src/tab_admin.cpp index 615471e5..697644e7 100644 --- a/cockatrice/src/tab_admin.cpp +++ b/cockatrice/src/tab_admin.cpp @@ -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) { diff --git a/cockatrice/src/tab_admin.h b/cockatrice/src/tab_admin.h index cc5ae6a9..d0bd3148 100644 --- a/cockatrice/src/tab_admin.h +++ b/cockatrice/src/tab_admin.h @@ -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(); diff --git a/common/pb/admin_commands.proto b/common/pb/admin_commands.proto index 233ec532..b23f745d 100644 --- a/common/pb/admin_commands.proto +++ b/common/pb/admin_commands.proto @@ -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; + } +} diff --git a/servatrice/CMakeLists.txt b/servatrice/CMakeLists.txt index 2fe46e00..cc7f0792 100644 --- a/servatrice/CMakeLists.txt +++ b/servatrice/CMakeLists.txt @@ -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 diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index 22048ca0..db6bfeb8 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.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 -#ifdef Q_OS_UNIX -#include -#include -#include -#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); - - 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 + signalhandler = new SignalHandler(); + 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(); diff --git a/servatrice/src/main.h b/servatrice/src/main.h index 037e9bba..389b805c 100644 --- a/servatrice/src/main.h +++ b/servatrice/src/main.h @@ -2,6 +2,11 @@ #define MAIN_H class ServerLogger; +class QThread; +class SettingsCache; + extern ServerLogger *logger; +extern QThread *loggerThread; +extern SettingsCache *settingsCache; #endif diff --git a/servatrice/src/server_logger.cpp b/servatrice/src/server_logger.cpp index 3fd9c925..ee411d0f 100644 --- a/servatrice/src/server_logger.cpp +++ b/servatrice/src/server_logger.cpp @@ -1,17 +1,11 @@ #include "server_logger.h" #include "settingscache.h" -#include #include #include #include #include #include #include -#ifdef Q_OS_UNIX -# include -# include -# include -#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]; diff --git a/servatrice/src/server_logger.h b/servatrice/src/server_logger.h index 67b293cf..478d0460 100644 --- a/servatrice/src/server_logger.h +++ b/servatrice/src/server_logger.h @@ -7,7 +7,6 @@ #include #include -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; diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index a2fa26b2..10c9bd73 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -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; +} diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index c89709d3..662f1346 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -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); diff --git a/servatrice/src/signalhandler.cpp b/servatrice/src/signalhandler.cpp new file mode 100644 index 00000000..4854d270 --- /dev/null +++ b/servatrice/src/signalhandler.cpp @@ -0,0 +1,98 @@ +#include + +#include "signalhandler.h" +#include "server_logger.h" +#include "settingscache.h" +#include "main.h" + +#ifdef Q_OS_UNIX +#include +#include +#include +#include +#include +#include +#include +#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); +} + diff --git a/servatrice/src/signalhandler.h b/servatrice/src/signalhandler.h new file mode 100644 index 00000000..314afa3b --- /dev/null +++ b/servatrice/src/signalhandler.h @@ -0,0 +1,24 @@ +#ifndef SIGNALHANDLER_H +#define SIGNALHANDLER_H + +#include + +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