Some changes

This commit is contained in:
WolverinDEV 2019-08-25 22:16:42 +02:00
parent 787f911b6f
commit 79f8c91157
17 changed files with 320 additions and 119 deletions

@ -1 +1 @@
Subproject commit 535d63f039b3e0b0559e7e09a5c80b04111fe93f Subproject commit 0063a5acb2f6f5af91ca1d06dd27f432ec78e8a9

View File

@ -12,6 +12,7 @@
#include <misc/base64.h> #include <misc/base64.h>
#include <misc/digest.h> #include <misc/digest.h>
#include <fstream>
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -24,6 +25,7 @@ using namespace license;
* Requests (license) / ip: SELECT DISTINCT `ip`, COUNT(`ip`) FROM `license_request` WHERE `keyId` = ? GROUP BY `ip` * Requests (license) / ip: SELECT DISTINCT `ip`, COUNT(`ip`) FROM `license_request` WHERE `keyId` = ? GROUP BY `ip`
* *
* SELECT DISTINCT(`ip`), `keyId` FROM `license_request` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000 * SELECT DISTINCT(`ip`), `keyId` FROM `license_request` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000
* //462
* *
* SELECT DISTINCT(`ip`), `license_request`.`keyId`, `license_info`.`username` FROM `license_request` LEFT JOIN `license_info` ON `license_info`.`keyId` = `license_request`.`keyId` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000 * SELECT DISTINCT(`ip`), `license_request`.`keyId`, `license_info`.`username` FROM `license_request` LEFT JOIN `license_info` ON `license_info`.`keyId` = `license_request`.`keyId` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000
* *
@ -110,9 +112,15 @@ int main(int argc, char** argv) {
} }
} }
return 0; return 0;
{ */
/*
{
ofstream _file_out("version_history.txt");
auto _now = system_clock::now(); auto _now = system_clock::now();
auto statistics = license_manager->list_statistics_version(_now - hours(24) * 9, _now, duration_cast<milliseconds>(hours(1))); cout << "Getting statistics" << endl;
auto statistics = license_manager->list_statistics_version(_now - hours(24) * 32 * 12, _now, duration_cast<milliseconds>(hours(1)));
cout << "Grouping statistics" << endl;
std::deque<std::string> versions; std::deque<std::string> versions;
const auto version_name = [](const std::string& key) { const auto version_name = [](const std::string& key) {
auto space = key.find(' '); auto space = key.find(' ');
@ -130,6 +138,7 @@ int main(int argc, char** argv) {
versions.push_back(name); versions.push_back(name);
} }
} }
cout << "Sorting statistics" << endl;
sort(versions.begin(), versions.end(), [](const std::string& a, const std::string& b) { sort(versions.begin(), versions.end(), [](const std::string& a, const std::string& b) {
const auto index_a = a.find_last_of('.'); const auto index_a = a.find_last_of('.');
const auto index_b = b.find_last_of('.'); const auto index_b = b.find_last_of('.');
@ -141,10 +150,11 @@ int main(int argc, char** argv) {
return patch_a > patch_b; return patch_a > patch_b;
}); });
cout << "Date"; cout << "Writing statistics" << endl;
for(auto it = versions.begin(); it != versions.end(); it++) _file_out << "Date";
cout << "," << *it; for(auto & version : versions)
cout << endl; _file_out << "," << version;
_file_out << endl;
for(const auto& entry : statistics) { for(const auto& entry : statistics) {
auto time = system_clock::to_time_t(entry->timestamp); auto time = system_clock::to_time_t(entry->timestamp);
@ -158,14 +168,17 @@ int main(int argc, char** argv) {
version_count[name] += version.second; version_count[name] += version.second;
} }
cout << string_time; _file_out << string_time;
for(const auto& name : versions) { for(const auto& name : versions) {
cout << "," << version_count[name]; _file_out << "," << version_count[name];
} }
cout << endl; _file_out << endl;
} }s
} cout << "Done statistics" << endl;
*/ _file_out.flush();
}
return 0;
*/
ssl_manager = make_shared<ts::ssl::SSLManager>(); ssl_manager = make_shared<ts::ssl::SSLManager>();
{ {

View File

@ -45,7 +45,7 @@ message ServerValidation {
} }
message LicenseResponse { message LicenseResponse {
required bool valid = 1; required bool valid = 1; //If set the license is valid. The blacklist field could still be active. If the flag is false then the blacklist will container the message
required Blacklist blacklist = 2; required Blacklist blacklist = 2;
optional LicenseInfo license_info = 3; //Only availible when ServerValidation::license_info = true optional LicenseInfo license_info = 3; //Only availible when ServerValidation::license_info = true
} }

View File

@ -305,43 +305,117 @@ bool LicenseManager::logStatistic(const std::string &key, const std::string& uni
return true; return true;
} }
std::deque<std::unique_ptr<LicenseManager::GlobalUserStatistics>> LicenseManager::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) { std::shared_ptr<LicenseManager::UserHistory> LicenseManager::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) {
map<std::string, deque<unique_ptr<LicenseManager::UserStatistics>>> server_statistics;
auto timeout = hours(2) + minutes(10); //TODO timeout configurable? auto timeout = hours(2) + minutes(10); //TODO timeout configurable?
auto state = command(this->database,"SELECT * FROM `history_online` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC", /* initialize the result */
auto allocated_records = (size_t) floor((end - begin) / interval) + 1;
auto _result = (UserHistory*) malloc(sizeof(UserHistory) + sizeof(GlobalUserStatistics) * allocated_records);
new (_result) UserHistory();
auto result = shared_ptr<UserHistory>(_result, [](UserHistory* ptr){
ptr->~UserHistory();
free(ptr);
});
result->record_count = 0;
result->begin = begin;
result->end = end;
result->interval = interval;
memset(&result->history[0], 0, allocated_records * sizeof(GlobalUserStatistics));
auto info = &_result->history[0];
/* temp db variables */
map<std::string, LicenseManager::DatabaseUserStatistics> server_statistics;
bool have_key, have_uid;
LicenseManager::DatabaseUserStatistics temp_stats; /* temp struct for stats parsing */
LicenseManager::DatabaseUserStatistics* stats_ptr; /* pointer to the target stats */
std::chrono::system_clock::time_point current_timestamp = begin + interval; /* upper limit of the current interval */
auto state = command(this->database, "SELECT * FROM `history_online` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()}, variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()},
variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()} variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()}
).query([&server_statistics](int columns, std::string* values, std::string* names){ ).query([&](int columns, std::string* values, std::string* names) {
size_t key_id = 0; /* find the user statistic ptr */
std::string unique_id; {
auto info = make_unique<LicenseManager::UserStatistics>(); size_t key_id = 0;
std::string unique_id;
have_key = false;
have_uid = false;
for(int index = 0; index < columns; index++) {
try {
if(names[index] == "keyId") {
key_id = stoull(values[index]);
have_key = true;
} else if(names[index] == "unique_id") {
unique_id = values[index];
have_uid = true;
} else {
continue;
}
if(have_key && have_uid)
break;
} catch (std::exception& ex) {
logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")");
return 0;
}
}
if(!have_key || !have_uid) return 0; //TODO: May log a warning
if(key_id == 0) return 0;
stats_ptr = &server_statistics[to_string(key_id) + "_" + unique_id];
}
for(int index = 0; index < columns; index++) { for(int index = 0; index < columns; index++) {
try { try {
if(names[index] == "keyId") if(names[index] == "timestamp")
key_id = stoull(values[index]); temp_stats.timestamp = system_clock::time_point() + milliseconds(stoll(values[index]));
else if(names[index] == "unique_id")
unique_id = values[index];
else if(names[index] == "timestamp")
info->timestamp = system_clock::time_point() + milliseconds(stoll(values[index]));
else if(names[index] == "server") else if(names[index] == "server")
info->servers_online = stoull(values[index]); temp_stats.servers_online = stoull(values[index]);
else if(names[index] == "clients") else if(names[index] == "clients")
info->clients_online = stoull(values[index]); temp_stats.clients_online = stoull(values[index]);
else if(names[index] == "web") else if(names[index] == "web")
info->web_clients_online = stoull(values[index]); temp_stats.web_clients_online = stoull(values[index]);
else if(names[index] == "music") else if(names[index] == "music")
info->bots_online = stoull(values[index]); temp_stats.bots_online = stoull(values[index]);
else if(names[index] == "queries") else if(names[index] == "queries")
info->queries_online = stoull(values[index]); temp_stats.queries_online = stoull(values[index]);
} catch (std::exception& ex) { } catch (std::exception& ex) {
logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")"); logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")");
return 0; return 0;
} }
} }
if(key_id == 0) return 0;
server_statistics[to_string(key_id) + "_" + unique_id].push_back(std::move(info)); /* because the query could only be oldest to newest */
while(temp_stats.timestamp > current_timestamp) {
assert(_result->record_count < allocated_records); /* ensure we write to valid memory */
auto min_timestamp = current_timestamp - timeout;
for(auto& server : server_statistics) {
auto& second = server.second;
if(second.timestamp < min_timestamp || second.timestamp.time_since_epoch().count() == 0)
continue; /* last server request is too old to be counted */
info->instance_online++;
info->queries_online += second.queries_online;
info->bots_online += second.bots_online;
info->web_clients_online += second.web_clients_online;
info->clients_online += second.clients_online;
info->servers_online += second.servers_online;
}
info++;
_result->record_count++;
current_timestamp += interval; /* lets gather for the next interval */
}
/* write the "new" statistic */
memcpy(stats_ptr, &temp_stats, sizeof(temp_stats));
return 0; return 0;
}); });
@ -350,41 +424,28 @@ std::deque<std::unique_ptr<LicenseManager::GlobalUserStatistics>> LicenseManager
return {}; return {};
} }
std::deque<std::unique_ptr<LicenseManager::GlobalUserStatistics>> result; /* flush the last record */
system_clock::time_point current_timestamp = begin; do {
while(current_timestamp <= end) { assert(_result->record_count < allocated_records); /* ensure we write to valid memory */
auto info = make_unique<LicenseManager::GlobalUserStatistics>();
info->timestamp = current_timestamp;
auto min_timestamp = current_timestamp - timeout;
for(auto& server : server_statistics) { for(auto& server : server_statistics) {
while(!server.second.empty()) { auto& second = server.second;
auto& first = *server.second.begin(); if(second.timestamp < min_timestamp)
if(first->timestamp > current_timestamp) break; //Entry within the future continue; /* last server request is too old to be counted */
if(first->timestamp + timeout < current_timestamp) { //Entry within the past
server.second.pop_front();
continue;
}
if(server.second.size() > 1) {
auto& second = *(server.second.begin() + 1);
if(second->timestamp <= current_timestamp) {
server.second.pop_front(); //The next entry is more up 2 date
continue;
}
}
info->instance_online++; info->instance_online++;
info->queries_online += first->queries_online; info->queries_online += second.queries_online;
info->bots_online += first->bots_online; info->bots_online += second.bots_online;
info->web_clients_online += first->web_clients_online; info->web_clients_online += second.web_clients_online;
info->clients_online += first->clients_online; info->clients_online += second.clients_online;
info->servers_online += first->servers_online; info->servers_online += second.servers_online;
break;
}
} }
result.push_back(std::move(info)); info++;
_result->record_count++;
current_timestamp += interval; current_timestamp += interval;
} } while(current_timestamp < end);
return result; return result;
} }
@ -393,7 +454,7 @@ std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> LicenseMana
map<std::string, deque<unique_ptr<LicenseManager::GlobalVersionsStatistic>>> server_statistics; map<std::string, deque<unique_ptr<LicenseManager::GlobalVersionsStatistic>>> server_statistics;
auto timeout = hours(2) + minutes(10); //TODO timeout configurable? auto timeout = hours(2) + minutes(10); //TODO timeout configurable?
auto state = command(this->database,"SELECT * FROM `history_version` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC", auto state = command(this->database, "SELECT * FROM `history_version` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()}, variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()},
variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()} variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()}
).query([&server_statistics](int columns, std::string* values, std::string* names){ ).query([&server_statistics](int columns, std::string* values, std::string* names){

View File

@ -29,13 +29,13 @@ namespace license {
threads::Mutex entry_update_lock; threads::Mutex entry_update_lock;
std::deque<CacheEntry*> entries; std::deque<CacheEntry*> entries;
}; };
struct UserStatistics { struct UserStatistics {
std::chrono::system_clock::time_point timestamp; uint64_t clients_online = 0;
uint64_t clients_online; uint64_t web_clients_online = 0;
uint64_t web_clients_online; uint64_t bots_online = 0;
uint64_t bots_online; uint64_t queries_online = 0;
uint64_t queries_online; uint64_t servers_online = 0;
uint64_t servers_online;
}; };
struct ExtendedUserStatistics : public UserStatistics{ struct ExtendedUserStatistics : public UserStatistics{
@ -43,13 +43,28 @@ namespace license {
}; };
struct GlobalUserStatistics : public UserStatistics { struct GlobalUserStatistics : public UserStatistics {
uint64_t instance_online; uint64_t instance_online = 0;
};
struct DatabaseUserStatistics : public UserStatistics {
std::chrono::system_clock::time_point timestamp{};
}; };
struct GlobalVersionsStatistic { struct GlobalVersionsStatistic {
std::chrono::system_clock::time_point timestamp; std::chrono::system_clock::time_point timestamp;
std::map<std::string, uint32_t> versions; std::map<std::string, uint32_t> versions;
}; };
struct UserHistory {
std::chrono::system_clock::time_point begin{};
std::chrono::system_clock::time_point end{};
std::chrono::milliseconds interval{0};
size_t record_count = 0;
GlobalUserStatistics history[0];
};
static_assert(sizeof(UserHistory) == 32);
public: public:
LicenseManager(sql::SqlManager* database); LicenseManager(sql::SqlManager* database);
~LicenseManager(); ~LicenseManager();
@ -68,7 +83,7 @@ namespace license {
bool logRequest(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const std::string& /* version */, int /* result */); bool logRequest(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const std::string& /* version */, int /* result */);
bool logStatistic(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const ts::proto::license::PropertyUpdateRequest&); bool logStatistic(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const ts::proto::license::PropertyUpdateRequest&);
//std::deque<std::unique_ptr<ExtendedUserStatistics>> list_statistics_user(const std::string& key, const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end); //std::deque<std::unique_ptr<ExtendedUserStatistics>> list_statistics_user(const std::string& key, const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end);
std::deque<std::unique_ptr<GlobalUserStatistics>> list_statistics_user(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */); std::shared_ptr<UserHistory> list_statistics_user(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
std::deque<std::unique_ptr<GlobalVersionsStatistic>> list_statistics_version(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */); std::deque<std::unique_ptr<GlobalVersionsStatistic>> list_statistics_version(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
inline sql::SqlManager* sql() { return this->database; } inline sql::SqlManager* sql() { return this->database; }

View File

@ -49,6 +49,8 @@ namespace license {
std::string key; std::string key;
std::string unique_identifier; std::string unique_identifier;
bool invalid_license = false;
void init(); void init();
void uninit(); void uninit();
void sendPacket(const protocol::packet&); void sendPacket(const protocol::packet&);

View File

@ -95,14 +95,25 @@ bool LicenseServer::handleDisconnect(shared_ptr<ConnectedClient>& client, protoc
inline void fill_info(proto::license::LicenseInfo* proto, const shared_ptr<LicenseInfo>& info, const std::string& key) { inline void fill_info(proto::license::LicenseInfo* proto, const shared_ptr<LicenseInfo>& info, const std::string& key) {
proto->set_key(key); proto->set_key(key);
proto->set_username(info->username); if(info) {
proto->set_first_name(info->first_name); proto->set_username(info->username);
proto->set_last_name(info->last_name); proto->set_first_name(info->first_name);
proto->set_email(info->email); proto->set_last_name(info->last_name);
proto->set_type(info->type); proto->set_email(info->email);
proto->set_created(duration_cast<milliseconds>(info->creation.time_since_epoch()).count()); proto->set_type(info->type);
proto->set_begin(duration_cast<milliseconds>(info->start.time_since_epoch()).count()); proto->set_created(duration_cast<milliseconds>(info->creation.time_since_epoch()).count());
proto->set_end(duration_cast<milliseconds>(info->end.time_since_epoch()).count()); proto->set_begin(duration_cast<milliseconds>(info->start.time_since_epoch()).count());
proto->set_end(duration_cast<milliseconds>(info->end.time_since_epoch()).count());
} else {
proto->set_username("invalid (null)");
proto->set_first_name("invalid (null)");
proto->set_last_name("invalid (null)");
proto->set_email("invalid (null)");
proto->set_type(0);
proto->set_created(0);
proto->set_begin(0);
proto->set_end(0);
}
} }
std::string string_to_hex(const std::string& input) std::string string_to_hex(const std::string& input)
@ -154,7 +165,9 @@ bool LicenseServer::handleServerValidation(shared_ptr<ConnectedClient> &client,
client->unique_identifier = pkt.info().has_unique_id() ? pkt.info().unique_id() : client->address(); client->unique_identifier = pkt.info().has_unique_id() ? pkt.info().unique_id() : client->address();
if(remoteLicense && pkt.licensed()) { if(remoteLicense && pkt.licensed()) {
auto info = this->manager->licenseInfo(remoteLicense->key()); auto info = this->manager->licenseInfo(remoteLicense->key());
if(!info) { if(!info) {
response.mutable_blacklist()->set_reason("License hasn't been found.");
response.set_valid(false); response.set_valid(false);
/* /*
@ -179,6 +192,7 @@ bool LicenseServer::handleServerValidation(shared_ptr<ConnectedClient> &client,
logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license hasn't been found in database. Shutting down server!", client->address()); logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license hasn't been found in database. Shutting down server!", client->address());
} else { } else {
if(info->deleted) { if(info->deleted) {
response.mutable_blacklist()->set_reason("License has been deleted.");
response.set_valid(false); response.set_valid(false);
logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license has been deleted! Shutting down server!", client->address()); logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license has been deleted! Shutting down server!", client->address());
} else { } else {
@ -191,7 +205,15 @@ bool LicenseServer::handleServerValidation(shared_ptr<ConnectedClient> &client,
response.set_valid(true); response.set_valid(true);
} }
response.mutable_blacklist()->set_state(ts::proto::license::VALID); if(response.valid())
response.mutable_blacklist()->set_state(ts::proto::license::VALID);
else {
if(!response.has_license_info())
fill_info(response.mutable_license_info(), nullptr, ""); /* "Hack" for old clients which require a license. Else the server would not be stopped */
response.mutable_blacklist()->set_state(ts::proto::license::BLACKLISTED); /* "Hack" for all old clients */
client->invalid_license = true;
}
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_VALIDATION_RESPONSE, response}); client->sendPacket(protocol::packet{protocol::PACKET_SERVER_VALIDATION_RESPONSE, response});
client->protocol.state = protocol::PROPERTY_ADJUSTMENT; client->protocol.state = protocol::PROPERTY_ADJUSTMENT;
return true; return true;
@ -199,6 +221,18 @@ bool LicenseServer::handleServerValidation(shared_ptr<ConnectedClient> &client,
bool LicenseServer::handlePacketPropertyUpdate(shared_ptr<ConnectedClient> &client, protocol::packet &packet, std::string &error) { bool LicenseServer::handlePacketPropertyUpdate(shared_ptr<ConnectedClient> &client, protocol::packet &packet, std::string &error) {
TEST_PROTOCOL_STATE(PROPERTY_ADJUSTMENT); TEST_PROTOCOL_STATE(PROPERTY_ADJUSTMENT);
if(client->invalid_license) {
ts::proto::license::PropertyUpdateResponse response;
response.set_accepted(true);
response.set_reset_speach(0);
response.set_speach_total_remote(0);
response.set_speach_varianz_corrector(0);
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT, response});
this->disconnectClient(client, "finished");
/* Not sure if we really want here to log these data. May put a lvalid=false within the db? */
return true;
}
PARSE_PROTO(PropertyUpdateRequest, pkt); PARSE_PROTO(PropertyUpdateRequest, pkt);
logMessage("[CLIENT][" + client->address() + "] Got server statistics:"); logMessage("[CLIENT][" + client->address() + "] Got server statistics:");

View File

@ -34,9 +34,9 @@ namespace license {
std::chrono::system_clock::time_point begin; std::chrono::system_clock::time_point begin;
std::chrono::system_clock::time_point end; std::chrono::system_clock::time_point end;
std::chrono::milliseconds period; std::chrono::milliseconds period;
HistoryType type; HistoryType type;
std::deque<std::unique_ptr<server::LicenseManager::GlobalUserStatistics>> statistics; std::shared_ptr<server::LicenseManager::UserHistory> statistics;
}; };
class StatisticManager { class StatisticManager {

View File

@ -462,13 +462,14 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
response["history"]["end"] = duration_cast<milliseconds>(history->end.time_since_epoch()).count(); response["history"]["end"] = duration_cast<milliseconds>(history->end.time_since_epoch()).count();
response["history"]["interval"] = duration_cast<milliseconds>(history->period).count(); response["history"]["interval"] = duration_cast<milliseconds>(history->period).count();
int index = 0;
for(auto& element : history->statistics) { int index;
response["history"]["data"][index]["instances"] = element->instance_online; auto stats = history->statistics;
response["history"]["data"][index]["servers"] = element->servers_online; for(index = 0; index < stats->record_count; index++) {
response["history"]["data"][index]["clients"] = element->clients_online; response["history"]["data"][index]["instances"] = stats->history[index].instance_online;
response["history"]["data"][index]["music"] = element->bots_online; response["history"]["data"][index]["servers"] = stats->history[index].servers_online;
index++; response["history"]["data"][index]["clients"] = stats->history[index].clients_online;
response["history"]["data"][index]["music"] = stats->history[index].bots_online;
} }
lock_guard lock(client->execute_lock); lock_guard lock(client->execute_lock);

View File

@ -101,7 +101,7 @@ namespace license {
inline std::string key() { return std::string(data.licenceKey, 64); } inline std::string key() { return std::string(data.licenceKey, 64); }
inline std::chrono::time_point<std::chrono::system_clock> end() { return std::chrono::system_clock::time_point() + std::chrono::milliseconds(this->data.endTimestamp); } inline std::chrono::time_point<std::chrono::system_clock> end() { return std::chrono::system_clock::time_point() + std::chrono::milliseconds(this->data.endTimestamp); }
inline std::string owner() { return std::string(this->data.licenceOwner); } inline std::string owner() { return std::string(this->data.licenceOwner); } //Scopetita
inline bool isValid() { return data.endTimestamp == 0 || std::chrono::system_clock::now() < this->end(); } inline bool isValid() { return data.endTimestamp == 0 || std::chrono::system_clock::now() < this->end(); }
inline bool isPremium(){ return isPremiumLicense(data.type); } inline bool isPremium(){ return isPremiumLicense(data.type); }
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));

View File

@ -9,8 +9,17 @@ using namespace std;
using namespace std::chrono; using namespace std::chrono;
void LicenceRequest::handlePacketDisconnect(const std::string& message) { void LicenceRequest::handlePacketDisconnect(const std::string& message) {
if(this->state != protocol::DISCONNECTING) if(this->state != protocol::DISCONNECTING) {
LICENSE_FERR(this, UnexcpectedDisconnectException, "Remote side closed the connection (" + message + ")"); /*
* We got an early disconnect.
* Test if we have a result. If so and the license is invalid then we could use that result
*/
if(this->response && !this->response->license_valid) {
this->currentFuture->executionSucceed(this->response);
} else {
LICENSE_FERR(this, UnexcpectedDisconnectException, "Remote side closed the connection unexpectedly (" + message + ")");
}
}
} }
void LicenceRequest::handlePacketHandshake(const std::string& data) { void LicenceRequest::handlePacketHandshake(const std::string& data) {
@ -48,7 +57,9 @@ void LicenceRequest::handlePacketLicenseInfo(const std::string& message) {
auto result = make_shared<LicenseRequestResponse>(); auto result = make_shared<LicenseRequestResponse>();
auto licenseInfo = make_shared<LicenseInfo>(); auto licenseInfo = make_shared<LicenseInfo>();
if(!response.has_license_info() && this->data->license) LICENSE_FERR(this, InvalidResponseException, "Missing license info"); if(!response.has_license_info() && this->data->license && response.valid() && response.blacklist().state() == ts::proto::license::VALID) {
LICENSE_FERR(this, InvalidResponseException, "Missing license info");
}
if(this->data->license) { if(this->data->license) {
licenseInfo->type = (LicenseType) response.license_info().type(); licenseInfo->type = (LicenseType) response.license_info().type();
@ -75,7 +86,6 @@ void LicenceRequest::handlePacketLicenseInfo(const std::string& message) {
result->license = licenseInfo; result->license = licenseInfo;
this->response = result; this->response = result;
ts::proto::license::PropertyUpdateRequest infos; ts::proto::license::PropertyUpdateRequest infos;
infos.set_speach_total(this->data->speach_total); infos.set_speach_total(this->data->speach_total);
infos.set_speach_dead(this->data->speach_dead); infos.set_speach_dead(this->data->speach_dead);

View File

@ -37,7 +37,7 @@ ConnectedClient::~ConnectedClient() {
memtrack::freed<ConnectedClient>(this); memtrack::freed<ConnectedClient>(this);
} }
std::shared_ptr<ConnectionInfoData> ConnectedClient::requestConnectionInfo(const std::shared_ptr<ConnectedClient>& receiver) { std::shared_ptr<ConnectionInfoData> ConnectedClient::request_connection_info(const std::shared_ptr<ConnectedClient> &receiver, bool& send_temp) {
auto& info = this->connection_info; auto& info = this->connection_info;
lock_guard info_lock(info.lock); lock_guard info_lock(info.lock);
@ -49,11 +49,17 @@ std::shared_ptr<ConnectionInfoData> ConnectedClient::requestConnectionInfo(const
info.data = nullptr; info.data = nullptr;
} }
info.receiver.erase(std::remove_if(info.receiver.begin(), info.receiver.end(), [&](const weak_ptr<ConnectedClient>& weak) { if(receiver) {
auto locked = weak.lock(); info.receiver.erase(std::remove_if(info.receiver.begin(), info.receiver.end(), [&](const weak_ptr<ConnectedClient>& weak) {
return !locked || locked == receiver; auto locked = weak.lock();
}), info.receiver.end()); if(locked == receiver) {
info.receiver.push_back(receiver); send_temp = true;
return true;
}
return !locked;
}), info.receiver.end());
info.receiver.push_back(receiver);
}
if(chrono::system_clock::now() - info.last_requested >= chrono::seconds(1)) { if(chrono::system_clock::now() - info.last_requested >= chrono::seconds(1)) {
info.last_requested = chrono::system_clock::now(); info.last_requested = chrono::system_clock::now();
@ -764,7 +770,7 @@ void ConnectedClient::sendServerInit() {
command["lt"] = LicenseType::LICENSE_HOSTING; command["lt"] = LicenseType::LICENSE_HOSTING;
} else } else
command["lt"] = ts::config::server::DefaultServerLicense; command["lt"] = ts::config::server::DefaultServerLicense;
command["pv"] = 6; //Protocol version command["pv"] = 6; //Protocol version
command["acn"] = this->getDisplayName(); command["acn"] = this->getDisplayName();
command["aclid"] = this->getClientId(); command["aclid"] = this->getClientId();
if(dynamic_cast<VoiceClient*>(this)) { if(dynamic_cast<VoiceClient*>(this)) {

View File

@ -157,7 +157,7 @@ namespace ts {
virtual bool notifyGroupPermList(const std::shared_ptr<Group>&, bool); virtual bool notifyGroupPermList(const std::shared_ptr<Group>&, bool);
virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionManager>&, bool); virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionManager>&, bool);
virtual bool notifyChannelGroupList(); virtual bool notifyChannelGroupList();
virtual bool notifyConnectionInfo(std::shared_ptr<ConnectedClient>,std::shared_ptr<ConnectionInfoData>); virtual bool notifyConnectionInfo(const std::shared_ptr<ConnectedClient> &target, const std::shared_ptr<ConnectionInfoData> &info);
virtual bool notifyChannelSubscribed(const std::deque<std::shared_ptr<BasicChannel>> &); virtual bool notifyChannelSubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
virtual bool notifyChannelUnsubscribed(const std::deque<std::shared_ptr<BasicChannel>> &); virtual bool notifyChannelUnsubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
@ -269,7 +269,7 @@ namespace ts {
bool shouldFloodBlock(); bool shouldFloodBlock();
virtual bool ignoresFlood() { return !this->block_flood; } virtual bool ignoresFlood() { return !this->block_flood; }
std::shared_ptr<ConnectionInfoData> requestConnectionInfo(const std::shared_ptr<ConnectedClient>& /* receiver */); std::shared_ptr<ConnectionInfoData> request_connection_info(const std::shared_ptr<ConnectedClient> & /* receiver */, bool& /* send temporary (no client response yet) */);
virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */); virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */);
void updateTalkRights(permission::PermissionValue talk_power); void updateTalkRights(permission::PermissionValue talk_power);

View File

@ -651,9 +651,13 @@ CommandResult ConnectedClient::handleCommandGetConnectionInfo(Command &cmd) {
auto client = this->server->findClient(cmd["clid"].as<ClientId>()); auto client = this->server->findClient(cmd["clid"].as<ClientId>());
if (!client) return {findError("client_invalid_id"), "invalid client id"}; if (!client) return {findError("client_invalid_id"), "invalid client id"};
auto info = client->requestConnectionInfo(_this.lock()); bool send_temp;
if (info) auto info = client->request_connection_info(_this.lock(), send_temp);
if (info) {
this->notifyConnectionInfo(client, info); this->notifyConnectionInfo(client, info);
} else if(send_temp) {
this->notifyConnectionInfo(client, nullptr);
}
return CommandResult::Success; return CommandResult::Success;
} }
@ -872,6 +876,7 @@ CommandResult ConnectedClient::handleCommandPermissionList(Command &cmd) {
if (!permission->clientSupported) continue; if (!permission->clientSupported) continue;
auto &blk = list_builder[index++]; auto &blk = list_builder[index++];
blk["permname"] = permission->name; blk["permname"] = permission->name;
blk["permdesc"] = permission->description; blk["permdesc"] = permission->description;
blk["permid"] = permission->type; blk["permid"] = permission->type;
@ -879,7 +884,7 @@ CommandResult ConnectedClient::handleCommandPermissionList(Command &cmd) {
return list_builder; return list_builder;
}; };
if(this->getType() == CLIENT_TEASPEAK || this->getType() == CLIENT_TEAMSPEAK || this->getType() == CLIENT_QUERY) { if((this->getType() == CLIENT_TEASPEAK || this->getType() == CLIENT_TEAMSPEAK || this->getType() == CLIENT_QUERY) && false) {
Command response(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifypermissionlist" : ""); Command response(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifypermissionlist" : "");
{ {
lock_guard lock(permission_list_string_lock); lock_guard lock(permission_list_string_lock);

View File

@ -11,6 +11,7 @@
#include <log/LogUtils.h> #include <log/LogUtils.h>
#include <misc/sassert.h> #include <misc/sassert.h>
#include <misc/timer.h> #include <misc/timer.h>
#include "./web/WebClient.h"
using namespace std::chrono; using namespace std::chrono;
using namespace std; using namespace std;
@ -247,16 +248,65 @@ bool ConnectedClient::notifyClientChannelGroupChanged(
return true; return true;
} }
bool ConnectedClient::notifyConnectionInfo(std::shared_ptr<ConnectedClient> target, std::shared_ptr<ConnectionInfoData> info) { bool ConnectedClient::notifyConnectionInfo(const shared_ptr<ConnectedClient> &target, const shared_ptr<ConnectionInfoData> &info) {
Command notify("notifyconnectioninfo"); Command notify("notifyconnectioninfo");
notify["clid"] = target->getClientId(); notify["clid"] = target->getClientId();
if(target->getClientId() != this->getClientId()){ if(target->getClientId() != this->getClientId()) {
for(const auto& elm : info->properties) /* default values which normally sets the client */
notify[elm.first] = elm.second; notify["connection_bandwidth_received_last_minute_control"] = -1;
notify["connection_connected_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->connectTimestamp).count(); notify["connection_bandwidth_received_last_minute_keepalive"] = -1;
notify["connection_filetransfer_bandwidth_sent"] = 0; notify["connection_bandwidth_received_last_minute_speech"] = -1;
notify["connection_filetransfer_bandwidth_received"] = 0; notify["connection_bandwidth_received_last_second_control"] = -1;
notify["connection_bandwidth_received_last_second_keepalive"] = -1;
notify["connection_bandwidth_received_last_second_speech"] = -1;
notify["connection_bandwidth_sent_last_minute_control"] = -1;
notify["connection_bandwidth_sent_last_minute_keepalive"] = -1;
notify["connection_bandwidth_sent_last_minute_speech"] = -1;
notify["connection_bandwidth_sent_last_second_control"] = -1;
notify["connection_bandwidth_sent_last_second_keepalive"] = -1;
notify["connection_bandwidth_sent_last_second_speech"] = -1;
notify["connection_bytes_received_control"] = -1;
notify["connection_bytes_received_keepalive"] = -1;
notify["connection_bytes_received_speech"] = -1;
notify["connection_bytes_sent_control"] = -1;
notify["connection_bytes_sent_keepalive"] = -1;
notify["connection_bytes_sent_speech"] = -1;
notify["connection_packets_received_control"] = -1;
notify["connection_packets_received_keepalive"] = -1;
notify["connection_packets_received_speech"] = -1;
notify["connection_packets_sent_control"] = -1;
notify["connection_packets_sent_keepalive"] = -1;
notify["connection_packets_sent_speech"] = -1;
notify["connection_server2client_packetloss_control"] = -1;
notify["connection_server2client_packetloss_keepalive"] = -1;
notify["connection_server2client_packetloss_speech"] = -1;
notify["connection_server2client_packetloss_total"] = -1;
notify["connection_ping"] = 0;
notify["connection_ping_deviation"] = 0;
notify["connection_connected_time"] = 0;
notify["connection_idle_time"] = 0;
notify["connection_filetransfer_bandwidth_sent"] = 0;
notify["connection_filetransfer_bandwidth_received"] = 0;
if(info) {
for(const auto& elm : info->properties) {
notify[elm.first] = elm.second;
}
} else {
//Fill in some server stuff
if(dynamic_pointer_cast<VoiceClient>(target))
notify["connection_ping"] = floor<milliseconds>(dynamic_pointer_cast<VoiceClient>(target)->calculatePing()).count();
else if(dynamic_pointer_cast<WebClient>(target))
notify["connection_ping"] = floor<milliseconds>(dynamic_pointer_cast<WebClient>(target)->client_ping()).count();
}
} }
if(target->getClientId() == this->getClientId() || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_remoteaddress_view, 1, target->currentChannel, true)) { if(target->getClientId() == this->getClientId() || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_remoteaddress_view, 1, target->currentChannel, true)) {
@ -264,11 +314,13 @@ bool ConnectedClient::notifyConnectionInfo(std::shared_ptr<ConnectedClient> targ
notify["connection_client_port"] = target->getPeerPort(); notify["connection_client_port"] = target->getPeerPort();
} }
notify["connection_client2server_packetloss_speech"] = 0.f; //Needs to be filled out
notify["connection_client2server_packetloss_keepalive"] = 0.f; notify["connection_client2server_packetloss_speech"] = -1;
notify["connection_client2server_packetloss_control"] = 0.f; notify["connection_client2server_packetloss_keepalive"] = -1;
notify["connection_client2server_packetloss_total"] = 0.f; notify["connection_client2server_packetloss_control"] = -1;
notify["connection_client2server_packetloss_total"] = -1;
notify["connection_connected_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->connectTimestamp).count();
notify["connection_idle_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->idleTimestamp).count(); notify["connection_idle_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->idleTimestamp).count();
this->sendCommand(notify); this->sendCommand(notify);
return true; return true;

View File

@ -90,7 +90,8 @@ void VoiceClient::tick(const std::chrono::system_clock::time_point &time) {
duration_cast<milliseconds>(time - this->lastPingRequest).count(), duration_cast<milliseconds>(time - this->lastPingRequest).count(),
duration_cast<milliseconds>(time - this->lastPingResponse).count()); duration_cast<milliseconds>(time - this->lastPingResponse).count());
this->requestConnectionInfo(nullptr); bool force;
this->request_connection_info(nullptr, force);
this->lastPingResponse = system_clock::now(); this->lastPingResponse = system_clock::now();
return; return;
} }

View File

@ -124,6 +124,7 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
initivexpand2["beta"] = base64::encode(this->crypto.beta); initivexpand2["beta"] = base64::encode(this->crypto.beta);
initivexpand2["omega"] = serverOmega; initivexpand2["omega"] = serverOmega;
initivexpand2["proof"] = proof; initivexpand2["proof"] = proof;
initivexpand2["tvd"] = "";
initivexpand2["root"] = base64::encode((char*) this->crypto.chain_data->public_key, 32); initivexpand2["root"] = base64::encode((char*) this->crypto.chain_data->public_key, 32);
initivexpand2["ot"] = 1; initivexpand2["ot"] = 1;