101 lines
4.5 KiB
C++
101 lines
4.5 KiB
C++
|
|
#include <breakpad/client/linux/handler/exception_handler.h>
|
|
#include "VirtualServer.h"
|
|
#include "SignalHandler.h"
|
|
#include "VirtualServerManager.h"
|
|
#include "InstanceHandler.h"
|
|
#include "ShutdownHelper.h"
|
|
#include <csignal>
|
|
#include <log/LogUtils.h>
|
|
#include <experimental/filesystem>
|
|
|
|
using namespace std;
|
|
namespace fs = std::experimental::filesystem;
|
|
|
|
google_breakpad::ExceptionHandler* globalExceptionHandler = nullptr;
|
|
#define SIG(s, c) \
|
|
if(signal(s, c) != nullptr) logError(LOG_GENERAL, "Cant setup signal handler for " #s);
|
|
|
|
|
|
extern bool mainThreadDone;
|
|
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) {
|
|
logCritical(LOG_GENERAL, "The server crashed!");
|
|
try {
|
|
if(!fs::exists(fs::u8path(ts::config::crash_path)))
|
|
fs::create_directories(fs::u8path(ts::config::crash_path));
|
|
|
|
auto path = fs::u8path(descriptor.path());
|
|
path = fs::u8path(ts::config::crash_path + "crash_dump_" + path.filename().string());
|
|
fs::rename(fs::u8path(descriptor.path()), path);
|
|
logCritical(LOG_GENERAL, "Wrote crash dump to " + path.relative_path().string());
|
|
} catch (...) {
|
|
logCritical(LOG_GENERAL, "Failed to write/move crash dump!");
|
|
}
|
|
if(std::current_exception()) {
|
|
logCritical(LOG_GENERAL, "Exception reached stack root and cause the server to crash!");
|
|
logCritical(LOG_GENERAL, " Type: {}", std::current_exception().__cxa_exception_type()->name());
|
|
try {
|
|
std::rethrow_exception(std::current_exception());
|
|
} catch(std::exception& ex) {
|
|
logCritical(LOG_GENERAL, " Message: {}", ex.what());
|
|
} catch(...) {}
|
|
}
|
|
logCritical(LOG_GENERAL, "Please report this crash to the TeaSpeak maintainer WolverinDEV");
|
|
logCritical(LOG_GENERAL, "Official issue and bug tracker url: https://github.com/TeaSpeak/TeaSpeak/issues");
|
|
logCritical(LOG_GENERAL, "Any reports of crashes are useless if you not provide the above generated crashlog!");
|
|
logCritical(LOG_GENERAL, "Stopping server");
|
|
ts::server::shutdownInstance(ts::config::messages::applicationCrashed);
|
|
while(!mainThreadDone) threads::self::sleep_for(chrono::seconds(1));
|
|
return succeeded;
|
|
}
|
|
|
|
std::atomic spawn_failed_count = 0;
|
|
bool ts::syssignal::setup() {
|
|
logMessage(LOG_GENERAL, "Setting up exception handler");
|
|
globalExceptionHandler = new google_breakpad::ExceptionHandler(google_breakpad::MinidumpDescriptor("."), nullptr, dumpCallback, nullptr, true, -1);
|
|
|
|
SIG(SIGTERM, &ts::syssignal::handleStopSignal);
|
|
if(isatty(fileno(stdin))) //We cant listen for this signal if stdin ist a atty
|
|
SIG(SIGINT, &ts::syssignal::handleStopSignal);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ts::syssignal::setup_threads() {
|
|
threads::set_global_error_handler([](auto error) {
|
|
if(error == threads::ThreadError::HANDLE_DELETE_UNDETACHED) {
|
|
logCritical(LOG_GENERAL, "Missed out thread detachment! This could lead to memory leaks!");
|
|
return threads::ThreadErrorAction::IGNORE;
|
|
} else if(error == threads::ThreadError::SPAWN_FAILED) {
|
|
logCritical(LOG_GENERAL, "Spawning a new thread failed!");
|
|
if(spawn_failed_count++ == 0) {
|
|
logCritical(LOG_GENERAL, "Stopping process!");
|
|
try {
|
|
std::thread([]{
|
|
ts::server::shutdownInstance("Failed to spawn new threads! Safety shutdown");
|
|
}).detach();
|
|
} catch(...) {
|
|
logCritical(LOG_GENERAL, "Failed to spawn shutdown thread (Of cause...). Stopping application directly!");
|
|
logCritical(LOG_GENERAL, "If this happens frequently dont forget to checkout std stderr channel for more information");
|
|
raise(SIGKILL);
|
|
}
|
|
}
|
|
return threads::ThreadErrorAction::RAISE;
|
|
}
|
|
|
|
return threads::ThreadErrorAction::RAISE;
|
|
});
|
|
return true;
|
|
}
|
|
|
|
atomic_int signal_count = 0;
|
|
void ts::syssignal::handleStopSignal(int signal) {
|
|
logMessageFmt(true, LOG_INSTANCE, "Got stop signal ({}). Stopping instance.", signal == SIGTERM ? "SIGTERM" :
|
|
signal == SIGINT ? "SIGINT" :
|
|
"UNKNOWN (" + to_string(signal) + ")");
|
|
if(signal_count++ >= 3) {
|
|
logMessageFmt(true, LOG_INSTANCE, "Got stop signal more that tree times. Force exiting instance.");
|
|
raise(SIGKILL);
|
|
}
|
|
ts::server::shutdownInstance();
|
|
} |