From 79f8c9115797f9e597230194b8116e6eac68f4a8 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 25 Aug 2019 22:16:42 +0200 Subject: [PATCH] Some changes --- git-teaspeak | 2 +- license/LicenseServerMain.cpp | 37 ++-- license/packets/LicenseRequest.proto | 2 +- license/server/LicenseManager.cpp | 161 ++++++++++++------ license/server/LicenseManager.h | 31 +++- license/server/LicenseServer.h | 2 + license/server/LicenseServerHandler.cpp | 52 +++++- license/server/StatisticManager.h | 4 +- license/server/WebAPI.cpp | 15 +- license/shared/License.h | 2 +- license/shared/LicenseRequestHandler.cpp | 18 +- server/src/client/ConnectedClient.cpp | 20 ++- server/src/client/ConnectedClient.h | 4 +- .../client/ConnectedClientCommandHandler.cpp | 11 +- .../client/ConnectedClientNotifyHandler.cpp | 74 ++++++-- server/src/client/voice/VoiceClient.cpp | 3 +- .../client/voice/VoiceClientHandschake.cpp | 1 + 17 files changed, 320 insertions(+), 119 deletions(-) diff --git a/git-teaspeak b/git-teaspeak index 535d63f..0063a5a 160000 --- a/git-teaspeak +++ b/git-teaspeak @@ -1 +1 @@ -Subproject commit 535d63f039b3e0b0559e7e09a5c80b04111fe93f +Subproject commit 0063a5acb2f6f5af91ca1d06dd27f432ec78e8a9 diff --git a/license/LicenseServerMain.cpp b/license/LicenseServerMain.cpp index ceb6baa..f65a753 100644 --- a/license/LicenseServerMain.cpp +++ b/license/LicenseServerMain.cpp @@ -12,6 +12,7 @@ #include #include +#include using namespace std; 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` * * 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 * @@ -110,9 +112,15 @@ int main(int argc, char** argv) { } } return 0; - { + */ + /* + { + ofstream _file_out("version_history.txt"); + auto _now = system_clock::now(); - auto statistics = license_manager->list_statistics_version(_now - hours(24) * 9, _now, duration_cast(hours(1))); + cout << "Getting statistics" << endl; + auto statistics = license_manager->list_statistics_version(_now - hours(24) * 32 * 12, _now, duration_cast(hours(1))); + cout << "Grouping statistics" << endl; std::deque versions; const auto version_name = [](const std::string& key) { auto space = key.find(' '); @@ -130,6 +138,7 @@ int main(int argc, char** argv) { versions.push_back(name); } } + cout << "Sorting statistics" << endl; sort(versions.begin(), versions.end(), [](const std::string& a, const std::string& b) { const auto index_a = a.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; }); - cout << "Date"; - for(auto it = versions.begin(); it != versions.end(); it++) - cout << "," << *it; - cout << endl; + cout << "Writing statistics" << endl; + _file_out << "Date"; + for(auto & version : versions) + _file_out << "," << version; + _file_out << endl; for(const auto& entry : statistics) { auto time = system_clock::to_time_t(entry->timestamp); @@ -158,14 +168,17 @@ int main(int argc, char** argv) { version_count[name] += version.second; } - cout << string_time; + _file_out << string_time; 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(); { diff --git a/license/packets/LicenseRequest.proto b/license/packets/LicenseRequest.proto index 965f9b4..25a3586 100644 --- a/license/packets/LicenseRequest.proto +++ b/license/packets/LicenseRequest.proto @@ -45,7 +45,7 @@ message ServerValidation { } 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; optional LicenseInfo license_info = 3; //Only availible when ServerValidation::license_info = true } diff --git a/license/server/LicenseManager.cpp b/license/server/LicenseManager.cpp index 4f95606..d8b0fc3 100644 --- a/license/server/LicenseManager.cpp +++ b/license/server/LicenseManager.cpp @@ -305,43 +305,117 @@ bool LicenseManager::logStatistic(const std::string &key, const std::string& uni return true; } -std::deque> LicenseManager::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) { - map>> server_statistics; +std::shared_ptr LicenseManager::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) { 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(_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 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(begin.time_since_epoch() - timeout).count()}, variable{":timestamp_end", duration_cast(end.time_since_epoch()).count()} - ).query([&server_statistics](int columns, std::string* values, std::string* names){ - size_t key_id = 0; - std::string unique_id; - auto info = make_unique(); + ).query([&](int columns, std::string* values, std::string* names) { + /* find the user statistic ptr */ + { + 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++) { try { - if(names[index] == "keyId") - key_id = stoull(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])); + if(names[index] == "timestamp") + temp_stats.timestamp = system_clock::time_point() + milliseconds(stoll(values[index])); else if(names[index] == "server") - info->servers_online = stoull(values[index]); + temp_stats.servers_online = stoull(values[index]); else if(names[index] == "clients") - info->clients_online = stoull(values[index]); + temp_stats.clients_online = stoull(values[index]); 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") - info->bots_online = stoull(values[index]); + temp_stats.bots_online = stoull(values[index]); else if(names[index] == "queries") - info->queries_online = stoull(values[index]); + temp_stats.queries_online = stoull(values[index]); } catch (std::exception& ex) { logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")"); 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; }); @@ -350,41 +424,28 @@ std::deque> LicenseManager return {}; } - std::deque> result; - system_clock::time_point current_timestamp = begin; - while(current_timestamp <= end) { - auto info = make_unique(); - info->timestamp = current_timestamp; + /* flush the last record */ + do { + assert(_result->record_count < allocated_records); /* ensure we write to valid memory */ + auto min_timestamp = current_timestamp - timeout; for(auto& server : server_statistics) { - while(!server.second.empty()) { - auto& first = *server.second.begin(); - if(first->timestamp > current_timestamp) break; //Entry within the future - 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; - } - } + auto& second = server.second; + if(second.timestamp < min_timestamp) + continue; /* last server request is too old to be counted */ - info->instance_online++; - info->queries_online += first->queries_online; - info->bots_online += first->bots_online; - info->web_clients_online += first->web_clients_online; - info->clients_online += first->clients_online; - info->servers_online += first->servers_online; - break; - } + 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; } - result.push_back(std::move(info)); + info++; + _result->record_count++; current_timestamp += interval; - } + } while(current_timestamp < end); return result; } @@ -393,7 +454,7 @@ std::deque> LicenseMana map>> server_statistics; 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(begin.time_since_epoch() - timeout).count()}, variable{":timestamp_end", duration_cast(end.time_since_epoch()).count()} ).query([&server_statistics](int columns, std::string* values, std::string* names){ diff --git a/license/server/LicenseManager.h b/license/server/LicenseManager.h index 633c914..713fea7 100644 --- a/license/server/LicenseManager.h +++ b/license/server/LicenseManager.h @@ -29,13 +29,13 @@ namespace license { threads::Mutex entry_update_lock; std::deque entries; }; + struct UserStatistics { - std::chrono::system_clock::time_point timestamp; - uint64_t clients_online; - uint64_t web_clients_online; - uint64_t bots_online; - uint64_t queries_online; - uint64_t servers_online; + uint64_t clients_online = 0; + uint64_t web_clients_online = 0; + uint64_t bots_online = 0; + uint64_t queries_online = 0; + uint64_t servers_online = 0; }; struct ExtendedUserStatistics : public UserStatistics{ @@ -43,13 +43,28 @@ namespace license { }; 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 { std::chrono::system_clock::time_point timestamp; std::map 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: LicenseManager(sql::SqlManager* database); ~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 logStatistic(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const ts::proto::license::PropertyUpdateRequest&); //std::deque> 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> 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 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> 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; } diff --git a/license/server/LicenseServer.h b/license/server/LicenseServer.h index 191b3c9..bf9ce11 100644 --- a/license/server/LicenseServer.h +++ b/license/server/LicenseServer.h @@ -49,6 +49,8 @@ namespace license { std::string key; std::string unique_identifier; + bool invalid_license = false; + void init(); void uninit(); void sendPacket(const protocol::packet&); diff --git a/license/server/LicenseServerHandler.cpp b/license/server/LicenseServerHandler.cpp index 9c816ed..ae8fb1c 100644 --- a/license/server/LicenseServerHandler.cpp +++ b/license/server/LicenseServerHandler.cpp @@ -95,14 +95,25 @@ bool LicenseServer::handleDisconnect(shared_ptr& client, protoc inline void fill_info(proto::license::LicenseInfo* proto, const shared_ptr& info, const std::string& key) { proto->set_key(key); - proto->set_username(info->username); - proto->set_first_name(info->first_name); - proto->set_last_name(info->last_name); - proto->set_email(info->email); - proto->set_type(info->type); - proto->set_created(duration_cast(info->creation.time_since_epoch()).count()); - proto->set_begin(duration_cast(info->start.time_since_epoch()).count()); - proto->set_end(duration_cast(info->end.time_since_epoch()).count()); + if(info) { + proto->set_username(info->username); + proto->set_first_name(info->first_name); + proto->set_last_name(info->last_name); + proto->set_email(info->email); + proto->set_type(info->type); + proto->set_created(duration_cast(info->creation.time_since_epoch()).count()); + proto->set_begin(duration_cast(info->start.time_since_epoch()).count()); + proto->set_end(duration_cast(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) @@ -154,7 +165,9 @@ bool LicenseServer::handleServerValidation(shared_ptr &client, client->unique_identifier = pkt.info().has_unique_id() ? pkt.info().unique_id() : client->address(); if(remoteLicense && pkt.licensed()) { auto info = this->manager->licenseInfo(remoteLicense->key()); + if(!info) { + response.mutable_blacklist()->set_reason("License hasn't been found."); response.set_valid(false); /* @@ -179,6 +192,7 @@ bool LicenseServer::handleServerValidation(shared_ptr &client, logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license hasn't been found in database. Shutting down server!", client->address()); } else { if(info->deleted) { + response.mutable_blacklist()->set_reason("License has been deleted."); response.set_valid(false); logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license has been deleted! Shutting down server!", client->address()); } else { @@ -191,7 +205,15 @@ bool LicenseServer::handleServerValidation(shared_ptr &client, 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->protocol.state = protocol::PROPERTY_ADJUSTMENT; return true; @@ -199,6 +221,18 @@ bool LicenseServer::handleServerValidation(shared_ptr &client, bool LicenseServer::handlePacketPropertyUpdate(shared_ptr &client, protocol::packet &packet, std::string &error) { 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); logMessage("[CLIENT][" + client->address() + "] Got server statistics:"); diff --git a/license/server/StatisticManager.h b/license/server/StatisticManager.h index 192c712..cf13ec6 100644 --- a/license/server/StatisticManager.h +++ b/license/server/StatisticManager.h @@ -34,9 +34,9 @@ namespace license { std::chrono::system_clock::time_point begin; std::chrono::system_clock::time_point end; std::chrono::milliseconds period; - HistoryType type; + HistoryType type; - std::deque> statistics; + std::shared_ptr statistics; }; class StatisticManager { diff --git a/license/server/WebAPI.cpp b/license/server/WebAPI.cpp index eab4597..82763ed 100644 --- a/license/server/WebAPI.cpp +++ b/license/server/WebAPI.cpp @@ -462,13 +462,14 @@ bool WebStatistics::handle_message(const std::shared_ptr(history->end.time_since_epoch()).count(); response["history"]["interval"] = duration_cast(history->period).count(); - int index = 0; - for(auto& element : history->statistics) { - response["history"]["data"][index]["instances"] = element->instance_online; - response["history"]["data"][index]["servers"] = element->servers_online; - response["history"]["data"][index]["clients"] = element->clients_online; - response["history"]["data"][index]["music"] = element->bots_online; - index++; + + int index; + auto stats = history->statistics; + for(index = 0; index < stats->record_count; index++) { + response["history"]["data"][index]["instances"] = stats->history[index].instance_online; + response["history"]["data"][index]["servers"] = stats->history[index].servers_online; + 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); diff --git a/license/shared/License.h b/license/shared/License.h index 5d850fc..6bbb482 100644 --- a/license/shared/License.h +++ b/license/shared/License.h @@ -101,7 +101,7 @@ namespace license { inline std::string key() { return std::string(data.licenceKey, 64); } inline std::chrono::time_point 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 isPremium(){ return isPremiumLicense(data.type); } } __attribute__ ((__packed__)); diff --git a/license/shared/LicenseRequestHandler.cpp b/license/shared/LicenseRequestHandler.cpp index a72acd8..6f09da5 100644 --- a/license/shared/LicenseRequestHandler.cpp +++ b/license/shared/LicenseRequestHandler.cpp @@ -9,8 +9,17 @@ using namespace std; using namespace std::chrono; void LicenceRequest::handlePacketDisconnect(const std::string& message) { - if(this->state != protocol::DISCONNECTING) - LICENSE_FERR(this, UnexcpectedDisconnectException, "Remote side closed the connection (" + message + ")"); + if(this->state != protocol::DISCONNECTING) { + /* + * 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) { @@ -48,7 +57,9 @@ void LicenceRequest::handlePacketLicenseInfo(const std::string& message) { auto result = make_shared(); auto licenseInfo = make_shared(); - 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) { licenseInfo->type = (LicenseType) response.license_info().type(); @@ -75,7 +86,6 @@ void LicenceRequest::handlePacketLicenseInfo(const std::string& message) { result->license = licenseInfo; this->response = result; - ts::proto::license::PropertyUpdateRequest infos; infos.set_speach_total(this->data->speach_total); infos.set_speach_dead(this->data->speach_dead); diff --git a/server/src/client/ConnectedClient.cpp b/server/src/client/ConnectedClient.cpp index 4034ee5..2bb0df8 100644 --- a/server/src/client/ConnectedClient.cpp +++ b/server/src/client/ConnectedClient.cpp @@ -37,7 +37,7 @@ ConnectedClient::~ConnectedClient() { memtrack::freed(this); } -std::shared_ptr ConnectedClient::requestConnectionInfo(const std::shared_ptr& receiver) { +std::shared_ptr ConnectedClient::request_connection_info(const std::shared_ptr &receiver, bool& send_temp) { auto& info = this->connection_info; lock_guard info_lock(info.lock); @@ -49,11 +49,17 @@ std::shared_ptr ConnectedClient::requestConnectionInfo(const info.data = nullptr; } - info.receiver.erase(std::remove_if(info.receiver.begin(), info.receiver.end(), [&](const weak_ptr& weak) { - auto locked = weak.lock(); - return !locked || locked == receiver; - }), info.receiver.end()); - info.receiver.push_back(receiver); + if(receiver) { + info.receiver.erase(std::remove_if(info.receiver.begin(), info.receiver.end(), [&](const weak_ptr& weak) { + auto locked = weak.lock(); + if(locked == 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)) { info.last_requested = chrono::system_clock::now(); @@ -764,7 +770,7 @@ void ConnectedClient::sendServerInit() { command["lt"] = LicenseType::LICENSE_HOSTING; } else command["lt"] = ts::config::server::DefaultServerLicense; - command["pv"] = 6; //Protocol version + command["pv"] = 6; //Protocol version command["acn"] = this->getDisplayName(); command["aclid"] = this->getClientId(); if(dynamic_cast(this)) { diff --git a/server/src/client/ConnectedClient.h b/server/src/client/ConnectedClient.h index 27f21f1..e1cf6a0 100644 --- a/server/src/client/ConnectedClient.h +++ b/server/src/client/ConnectedClient.h @@ -157,7 +157,7 @@ namespace ts { virtual bool notifyGroupPermList(const std::shared_ptr&, bool); virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr&, bool); virtual bool notifyChannelGroupList(); - virtual bool notifyConnectionInfo(std::shared_ptr,std::shared_ptr); + virtual bool notifyConnectionInfo(const std::shared_ptr &target, const std::shared_ptr &info); virtual bool notifyChannelSubscribed(const std::deque> &); virtual bool notifyChannelUnsubscribed(const std::deque> &); @@ -269,7 +269,7 @@ namespace ts { bool shouldFloodBlock(); virtual bool ignoresFlood() { return !this->block_flood; } - std::shared_ptr requestConnectionInfo(const std::shared_ptr& /* receiver */); + std::shared_ptr request_connection_info(const std::shared_ptr & /* receiver */, bool& /* send temporary (no client response yet) */); virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */); void updateTalkRights(permission::PermissionValue talk_power); diff --git a/server/src/client/ConnectedClientCommandHandler.cpp b/server/src/client/ConnectedClientCommandHandler.cpp index 21ff715..dd24f6a 100644 --- a/server/src/client/ConnectedClientCommandHandler.cpp +++ b/server/src/client/ConnectedClientCommandHandler.cpp @@ -651,9 +651,13 @@ CommandResult ConnectedClient::handleCommandGetConnectionInfo(Command &cmd) { auto client = this->server->findClient(cmd["clid"].as()); if (!client) return {findError("client_invalid_id"), "invalid client id"}; - auto info = client->requestConnectionInfo(_this.lock()); - if (info) + bool send_temp; + auto info = client->request_connection_info(_this.lock(), send_temp); + if (info) { this->notifyConnectionInfo(client, info); + } else if(send_temp) { + this->notifyConnectionInfo(client, nullptr); + } return CommandResult::Success; } @@ -872,6 +876,7 @@ CommandResult ConnectedClient::handleCommandPermissionList(Command &cmd) { if (!permission->clientSupported) continue; auto &blk = list_builder[index++]; + blk["permname"] = permission->name; blk["permdesc"] = permission->description; blk["permid"] = permission->type; @@ -879,7 +884,7 @@ CommandResult ConnectedClient::handleCommandPermissionList(Command &cmd) { 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" : ""); { lock_guard lock(permission_list_string_lock); diff --git a/server/src/client/ConnectedClientNotifyHandler.cpp b/server/src/client/ConnectedClientNotifyHandler.cpp index c41ce4c..827a0af 100644 --- a/server/src/client/ConnectedClientNotifyHandler.cpp +++ b/server/src/client/ConnectedClientNotifyHandler.cpp @@ -11,6 +11,7 @@ #include #include #include +#include "./web/WebClient.h" using namespace std::chrono; using namespace std; @@ -247,16 +248,65 @@ bool ConnectedClient::notifyClientChannelGroupChanged( return true; } -bool ConnectedClient::notifyConnectionInfo(std::shared_ptr target, std::shared_ptr info) { +bool ConnectedClient::notifyConnectionInfo(const shared_ptr &target, const shared_ptr &info) { Command notify("notifyconnectioninfo"); notify["clid"] = target->getClientId(); - if(target->getClientId() != this->getClientId()){ - for(const auto& elm : info->properties) - notify[elm.first] = elm.second; - notify["connection_connected_time"] = chrono::duration_cast(chrono::system_clock::now() - target->connectTimestamp).count(); - notify["connection_filetransfer_bandwidth_sent"] = 0; - notify["connection_filetransfer_bandwidth_received"] = 0; + if(target->getClientId() != this->getClientId()) { + /* default values which normally sets the client */ + notify["connection_bandwidth_received_last_minute_control"] = -1; + notify["connection_bandwidth_received_last_minute_keepalive"] = -1; + notify["connection_bandwidth_received_last_minute_speech"] = -1; + 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(target)) + notify["connection_ping"] = floor(dynamic_pointer_cast(target)->calculatePing()).count(); + else if(dynamic_pointer_cast(target)) + notify["connection_ping"] = floor(dynamic_pointer_cast(target)->client_ping()).count(); + } } 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 targ notify["connection_client_port"] = target->getPeerPort(); } - notify["connection_client2server_packetloss_speech"] = 0.f; - notify["connection_client2server_packetloss_keepalive"] = 0.f; - notify["connection_client2server_packetloss_control"] = 0.f; - notify["connection_client2server_packetloss_total"] = 0.f; + //Needs to be filled out + notify["connection_client2server_packetloss_speech"] = -1; + notify["connection_client2server_packetloss_keepalive"] = -1; + notify["connection_client2server_packetloss_control"] = -1; + notify["connection_client2server_packetloss_total"] = -1; + notify["connection_connected_time"] = chrono::duration_cast(chrono::system_clock::now() - target->connectTimestamp).count(); notify["connection_idle_time"] = chrono::duration_cast(chrono::system_clock::now() - target->idleTimestamp).count(); this->sendCommand(notify); return true; diff --git a/server/src/client/voice/VoiceClient.cpp b/server/src/client/voice/VoiceClient.cpp index ebf5ddd..856453b 100644 --- a/server/src/client/voice/VoiceClient.cpp +++ b/server/src/client/voice/VoiceClient.cpp @@ -90,7 +90,8 @@ void VoiceClient::tick(const std::chrono::system_clock::time_point &time) { duration_cast(time - this->lastPingRequest).count(), duration_cast(time - this->lastPingResponse).count()); - this->requestConnectionInfo(nullptr); + bool force; + this->request_connection_info(nullptr, force); this->lastPingResponse = system_clock::now(); return; } diff --git a/server/src/client/voice/VoiceClientHandschake.cpp b/server/src/client/voice/VoiceClientHandschake.cpp index e54f8bb..18db188 100644 --- a/server/src/client/voice/VoiceClientHandschake.cpp +++ b/server/src/client/voice/VoiceClientHandschake.cpp @@ -124,6 +124,7 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) { initivexpand2["beta"] = base64::encode(this->crypto.beta); initivexpand2["omega"] = serverOmega; initivexpand2["proof"] = proof; + initivexpand2["tvd"] = ""; initivexpand2["root"] = base64::encode((char*) this->crypto.chain_data->public_key, 32); initivexpand2["ot"] = 1;