Skip to content

Commit

Permalink
feat: added signal handlers, gracefully shutdown, stacktrace on excep…
Browse files Browse the repository at this point in the history
…tions, saving configs
  • Loading branch information
ABeltramo committed Apr 15, 2022
1 parent 8c4f1c5 commit cd5aa47
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 40 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/linux-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ jobs:
std: [ 17 ]
include:
- cxx: g++-9
other_pkgs: g++-9 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: g++-9 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
- cxx: g++-10
other_pkgs: g++-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: g++-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
- cxx: clang++-9
other_pkgs: clang-9 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: clang-9 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
- cxx: clang++-10
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
- cxx: clang++-10
build_type: Debug
std: 17
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
- cxx: clang++-10
build_type: Release
std: 17
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
other_pkgs: clang-10 libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Unit tests will live under `tests/`, they'll be focused on testing the library p
## Dependencies

```
cmake g++-10 gcc-10 libpipewire-0.3-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev
cmake g++-10 gcc-10 libpipewire-0.3-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libssl-dev libboost-stacktrace-dev
```

## Acknowledgements
Expand Down
24 changes: 23 additions & 1 deletion src/wolf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,31 @@ FetchContent_Declare(

FetchContent_MakeAvailable(fmtlib)

find_package(Boost REQUIRED COMPONENTS log_setup log)
find_package(Boost
REQUIRED COMPONENTS
log_setup
log
stacktrace_basic)
include_directories(${Boost_INCLUDE_DIRS})


### Boost stacktrace exception handling
# adapted from https://github.com/jschueller/boost-stacktrace-example/blob/master/CMakeLists.txt
# also see: https://www.boost.org/doc/libs/develop/doc/html/stacktrace/configuration_and_build.html
find_library(BOOST_STACKTRACE_BACKTRACE_LIBRARY NAMES boost_stacktrace_backtrace)
if (UNIX)
message(STATUS "Using Boost::stacktrace/addr2line")
add_definitions(-D_GNU_SOURCE=1)
target_compile_definitions(wolf PRIVATE BOOST_STACKTRACE_USE_ADDR2LINE)
target_link_libraries(wolf PRIVATE dl)
elseif (MINGW AND BOOST_STACKTRACE_BACKTRACE_LIBRARY)
message(STATUS "Using Boost::stacktrace/backtrace")
target_compile_definitions(wolf PRIVATE BOOST_STACKTRACE_USE_BACKTRACE)
target_link_libraries(wolf PRIVATE boost_stacktrace_backtrace backtrace)
else ()
message(STATUS "Using Boost::stacktrace/basic")
endif ()

# Some libraries don't work with FetchContent_Declare out of the box
# We have to manually git clone them and adding them into `libraries`
target_include_directories(wolf PRIVATE libraries .)
Expand Down
22 changes: 0 additions & 22 deletions src/wolf/rest/servers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,6 @@ using HttpServer = SimpleWeb::Server<SimpleWeb::HTTP>;

namespace HTTPServers {

/**
* @brief Create an HTTPS server
*
* @param pkey_filename
* @param cert_filename
* @return std::unique_ptr<HttpsServer>
*/
std::unique_ptr<HttpsServer> createHTTPS(const std::string &pkey_filename,
const std::string &cert_filename,
const std::shared_ptr<moonlight::Config> &config) {
return std::make_unique<HttpsServer>(cert_filename, pkey_filename, config);
}

/**
* @brief Create an HTTP server
*
* @return std::unique_ptr<HttpServer>
*/
std::unique_ptr<HttpServer> createHTTP() {
return std::make_unique<HttpServer>();
}

/**
* @brief Start the generic server on the specified port
* @return std::thread: the thread where this server will run
Expand Down
64 changes: 54 additions & 10 deletions src/wolf/wolf.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <vector>

#include <boost/filesystem.hpp>
#include <boost/stacktrace.hpp>
#include <csignal>
#include <helpers/logger.hpp>
#include <moonlight/config.hpp>
#include <moonlight/data-structures.hpp>
#include <rest/servers.cpp>
#include <vector>

/**
* @brief Will try to load the config file and fallback to defaults
Expand Down Expand Up @@ -58,17 +60,45 @@ initialize(const std::string &config_file, const std::string &pkey_filename, con
return std::make_shared<LocalState>(state);
}

/**
* Taken from: https://stackoverflow.com/questions/11468414/using-auto-and-lambda-to-handle-signal
* in order to have pass a lambda with variable capturing
*/
namespace {
std::function<void(int)> shutdown_handler;
void signal_handler(int signal) {
shutdown_handler(signal);
}
} // namespace

/**
* @brief: if an exception was raised we should have created a dump file, here we can pretty print it
*/
void check_exceptions() {
if (boost::filesystem::exists("./backtrace.dump")) {
std::ifstream ifs("./backtrace.dump");

auto st = boost::stacktrace::stacktrace::from_dump(ifs);
logs::log(logs::error, "Previous run crashed: \n{}", to_string(st));

// cleaning up
ifs.close();
boost::filesystem::remove("./backtrace.dump");
}
}

/**
* @brief here's where the magic starts
*/
int main(int argc, char *argv[]) {
logs::init(logs::trace);
check_exceptions();

auto config_file = "config.json";
auto local_state = initialize(config_file, "key.pem", "cert.pem");

auto https_server = HTTPServers::createHTTPS("key.pem", "cert.pem", local_state->config);
auto http_server = HTTPServers::createHTTP();
auto https_server = std::make_unique<HttpsServer>("cert.pem", "key.pem", local_state->config);
auto http_server = std::make_unique<HttpServer>();

auto https_thread = HTTPServers::startServer(https_server.get(),
*local_state,
Expand All @@ -77,12 +107,26 @@ int main(int argc, char *argv[]) {
*local_state,
local_state->config->map_port(moonlight::Config::HTTP_PORT));

https_thread.join();
http_thread.join();
// Exception and termination handling
shutdown_handler = [&](int signum) {
logs::log(logs::info, "Received interrupt signal {}, clean exit", signum);
if (signum == SIGABRT || signum == SIGSEGV) {
auto trace_file = "./backtrace.dump";
logs::log(logs::info, "Dumping stacktrace to {}", trace_file);
boost::stacktrace::safe_dump_to(trace_file);
}

logs::log(logs::info, "Saving back current configuration to file: {}", config_file);
local_state->config->saveCurrentConfig(config_file);

// TODO: clean exit
exit(signum);
};
std::signal(SIGINT, signal_handler);
std::signal(SIGTERM, signal_handler);
std::signal(SIGQUIT, signal_handler);
std::signal(SIGSEGV, signal_handler);
std::signal(SIGABRT, signal_handler);

logs::log(logs::info, "Saving back current configuration to file: {}", config_file);
local_state->config->saveCurrentConfig(config_file);
return 0;
https_thread.join();
http_thread.join();
}

0 comments on commit cd5aa47

Please sign in to comment.