197 lines
7.4 KiB
C++
197 lines
7.4 KiB
C++
|
#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));
|
||
|
}
|