Teaspeak-Server/server/src/lincense/LicenseHelper.cpp

197 lines
7.4 KiB
C++
Raw Normal View History

#include <log/LogUtils.h>
#include <src/Configuration.h>
#include <arpa/inet.h>
#include <src/SignalHandler.h>
#include <src/ShutdownHelper.h>
#include "src/InstanceHandler.h"
#include "LicenseHelper.h"
using namespace license;
using namespace std;
using namespace std::chrono;
using namespace ts;
using namespace ts::server;
LicenseHelper::LicenseHelper() {
this->scheduled_request = system_clock::now() + seconds(rand() % 30); //Check in one minute
}
LicenseHelper::~LicenseHelper() {
if(this->request.prepare_thread.joinable())
this->request.prepare_thread.join();
{
unique_lock lock(this->request.current_lock);
if(this->request.current) {
auto request = move(this->request.current);
lock.unlock();
request->abortRequest();
}
}
}
inline string format_time(const system_clock::time_point& time) {
std::time_t now = system_clock::to_time_t(time);
std::tm * ptm = std::localtime(&now);
char buffer[128];
const auto length = std::strftime(buffer, 128, "%a, %d.%m.%Y %H:%M:%S", ptm);
return string(buffer, length);
}
void LicenseHelper::tick() {
lock_guard tick_lock(this->license_tick_lock);
bool verbose = config::license->isPremium();
{
lock_guard request_lock(this->request.current_lock);
if(this->request.current) {
auto promise = this->request.current->requestInfo();
if(promise.state() != threads::FutureState::WORKING){
auto exception = this->request.current->exception();
if(promise.state() == threads::FutureState::FAILED) {
this->handle_request_failed(verbose, exception ? exception->what() : "unknown");
this->request.current = nullptr; /* connection should be already closed */
return;
} else {
auto response = promise.waitAndGet(nullptr);
this->request.current = nullptr; /* connection should be already closed */
if(!response){
this->handle_request_failed(verbose, exception ? exception->what() : "invalid result (null)");
return;
}
if(!response->license_valid || !response->properties_valid){
if(!response->license_valid) {
if(config::license->isPremium()) logCritical("Could not validate license.");
else logCritical("Your server has been shutdown remotely!");
} else if(!response->properties_valid) {
logCritical("Property adjustment failed!");
} else
logCritical("Your license expired!");
logCritical("Stopping application!");
ts::server::shutdownInstance();
return;
} else {
this->scheduled_request = this->last_request + hours(2);
logMessage(LOG_INSTANCE, "License successfully validated! Scheduling next check at {}", format_time(this->scheduled_request));
if(response->speach_reset)
serverInstance->resetSpeechTime();
serverInstance->properties()[property::SERVERINSTANCE_SPOKEN_TIME_VARIANZ] = response->speach_varianz_adjustment;
{
lock_guard lock(this->request.info_lock);
this->request.info = response->license;
}
this->request_fail_count = 0;
this->last_successful_request = system_clock::now();
}
}
}
}
}
if(system_clock::now() > scheduled_request){
this->do_request(verbose);
}
}
void LicenseHelper::do_request(bool verbose) {
if(verbose) {
if(config::license && config::license->isPremium())
logMessage(LOG_INSTANCE, "Validating license");
else
logMessage(LOG_INSTANCE, "Validating instance integrity");
}
this->last_request = system_clock::now();
this->scheduled_request = this->last_request + minutes(10); /* some kind of timeout */
{
unique_lock lock(this->request.current_lock);
if(this->request.current) {
auto request = move(this->request.current);
lock.unlock();
if(verbose) {
auto promise = request->requestInfo();
if(promise.state() == threads::FutureState::WORKING) {
logMessage(LOG_INSTANCE, "Old check timed out (10 min). Running new one!");
}
}
request->abortRequest();
}
}
if(this->request.prepare_thread.joinable()) /* usually the preparation should not take too long */
this->request.prepare_thread.join();
this->request.prepare_thread = std::thread([&]{
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
#ifdef DO_LOCAL_REQUEST
auto license_host = gethostbyname("localhost");
server_addr.sin_addr.s_addr = ((in_addr*) license_host->h_addr)->s_addr;
#else
auto license_host = gethostbyname("license.teaspeak.de");
if(!license_host){
if(verbose) logError("Could not valid license! (1)");
return;
}
if(!license_host->h_addr){
if(verbose) logError("Could not valid license! (2)");
return;
}
server_addr.sin_addr.s_addr = ((in_addr*) license_host->h_addr)->s_addr;
logger::logger(0)->debug("Requesting server {}", inet_ntoa(server_addr.sin_addr));
int first = server_addr.sin_addr.s_addr >> 24;
if(first == 0 || first == 127 || first == 255) {
if(config::license->isPremium()) {
logError("You tried to nullroot 'license.teaspeak.de'!");
logCritical("Could not validate license!");
logCritical("Stopping server!");
ts::server::shutdownInstance();
return;
}
return;
}
#endif
server_addr.sin_port = htons(27786);
auto license_data = serverInstance->generateLicenseData();
auto request = make_shared<license::LicenceRequest>(license_data, server_addr);
request->verbose = false;
{
lock_guard lock(this->request.current_lock);
this->request.current = request;
request->requestInfo();
}
});
}
void LicenseHelper::handle_request_failed(bool verbose, const std::string& error) {
if(verbose) {
if(config::license && config::license->isPremium())
logError(LOG_INSTANCE, "License validation failed: {}", error);
else
logError(LOG_INSTANCE, "Instance integrity check failed: {}", error);
}
this->request_fail_count++;
milliseconds next_request;
if(this->request_fail_count <= 1)
next_request = minutes(1);
else if(this->request_fail_count <= 5)
next_request = minutes(5);
else if(this->request_fail_count <= 10)
next_request = minutes(10);
else
next_request = minutes(30);
this->scheduled_request = this->last_request + next_request;
if(verbose)
logMessage(LOG_INSTANCE, "Scheduling next check at {}", format_time(this->scheduled_request));
}