#include #include #include #include #include #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_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)); }