Some updates

This commit is contained in:
WolverinDEV 2020-04-10 23:29:51 +02:00
parent 74fa735004
commit 7ef77c3160
15 changed files with 124 additions and 97 deletions

@ -1 +1 @@
Subproject commit ed01d0360c5f980486e3bf83abdd3610d129aa7b Subproject commit 2da73d81d1ee4dcd9e4e7e06a4b7fdf2ee6074ea

View File

@ -13,7 +13,7 @@ using namespace std::chrono;
using namespace ts::server; using namespace ts::server;
VirtualServerManager::VirtualServerManager(InstanceHandler* handle) : handle(handle) { VirtualServerManager::VirtualServerManager(InstanceHandler* handle) : handle(handle) {
this->puzzles = new protocol::PuzzleManager(); this->puzzles = new udp::PuzzleManager{};
this->handshakeTickers = new threads::Scheduler(1, "handshake ticker"); this->handshakeTickers = new threads::Scheduler(1, "handshake ticker");
this->execute_loop = new event::EventExecutor("executor #"); this->execute_loop = new event::EventExecutor("executor #");
//this->join_loop = new event::EventExecutor("joiner #"); //this->join_loop = new event::EventExecutor("joiner #");
@ -67,7 +67,8 @@ bool VirtualServerManager::initialize(bool autostart) {
this->state = State::STARTING; this->state = State::STARTING;
logMessage(LOG_INSTANCE, "Generating server puzzles..."); logMessage(LOG_INSTANCE, "Generating server puzzles...");
auto start = system_clock::now(); auto start = system_clock::now();
this->puzzles->precomputePuzzles(config::voice::DefaultPuzzlePrecomputeSize); if(!this->puzzles->precompute_puzzles(config::voice::DefaultPuzzlePrecomputeSize))
logCritical(LOG_INSTANCE, "Failed to precompute RSA puzzles");
logMessage(LOG_INSTANCE, "Puzzles generated! Time required: " + to_string(duration_cast<milliseconds>(system_clock::now() - start).count()) + "ms"); logMessage(LOG_INSTANCE, "Puzzles generated! Time required: " + to_string(duration_cast<milliseconds>(system_clock::now() - start).count()) + "ms");
size_t serverCount = 0; size_t serverCount = 0;

View File

@ -57,7 +57,7 @@ namespace ts {
bool createServerSnapshot(Command &cmd, std::shared_ptr<VirtualServer> server, int version, std::string &error); bool createServerSnapshot(Command &cmd, std::shared_ptr<VirtualServer> server, int version, std::string &error);
std::shared_ptr<VirtualServer> createServerFromSnapshot(std::shared_ptr<VirtualServer> old, std::string, uint16_t, const ts::Command &, std::string &); std::shared_ptr<VirtualServer> createServerFromSnapshot(std::shared_ptr<VirtualServer> old, std::string, uint16_t, const ts::Command &, std::string &);
protocol::PuzzleManager* rsaPuzzles() { return this->puzzles; } udp::PuzzleManager* rsaPuzzles() { return this->puzzles; }
event::EventExecutor* get_join_loop() { return this->join_loop; } event::EventExecutor* get_join_loop() { return this->join_loop; }
event::EventExecutor* get_executor_loop() { return this->execute_loop; } event::EventExecutor* get_executor_loop() { return this->execute_loop; }
@ -80,7 +80,7 @@ namespace ts {
InstanceHandler* handle; InstanceHandler* handle;
threads::Mutex instanceLock; threads::Mutex instanceLock;
std::deque<std::shared_ptr<VirtualServer>> instances; std::deque<std::shared_ptr<VirtualServer>> instances;
protocol::PuzzleManager* puzzles = nullptr; udp::PuzzleManager* puzzles{nullptr};
event::EventExecutor* execute_loop = nullptr; event::EventExecutor* execute_loop = nullptr;
event::EventExecutor* join_loop = nullptr; event::EventExecutor* join_loop = nullptr;

View File

@ -742,7 +742,7 @@ void SpeakingClient::processJoin() {
unique_lock server_channel_lock(this->server->channel_tree_lock); unique_lock server_channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_lock); this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_lock);
this->subscribeChannel({this->currentChannel}, false, true); if(this->getType() != ClientType::CLIENT_TEAMSPEAK) this->subscribeChannel({this->currentChannel}, false, true); /* su "improve" the TS3 clients join speed we send the channel clients a bit later, when the TS3 client gets his own client variables */
} }
TIMING_STEP(timings, "join move "); TIMING_STEP(timings, "join move ");

View File

@ -39,17 +39,21 @@ using namespace ts::token;
command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) { command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
CMD_REQ_SERVER; CMD_REQ_SERVER;
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())}; ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
shared_lock tree_lock(this->channel_lock); {
shared_lock tree_lock(this->channel_lock);
if (!client || (client.client != this && !this->isClientVisible(client.client, false))) if (!client || (client.client != this && !this->isClientVisible(client.client, false)))
return command_result{error::client_invalid_id, ""}; return command_result{error::client_invalid_id, ""};
deque<const property::PropertyDescription*> props; deque<const property::PropertyDescription*> props;
for (auto &prop : client->properties()->list_properties(property::FLAG_CLIENT_VARIABLE, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) { for (auto &prop : client->properties()->list_properties(property::FLAG_CLIENT_VARIABLE, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
props.push_back(&prop.type()); props.push_back(&prop.type());
}
this->notifyClientUpdated(client.client, props, false);
} }
if(client.client == this && this->getType() == ClientType::CLIENT_TEAMSPEAK)
this->notifyClientUpdated(client.client, props, false); this->subscribeChannel({this->currentChannel}, true, true); /* lets show the clients in the current channel because we've not done that while joining (speed improvement ;))*/
return command_result{error::ok}; return command_result{error::ok};
} }

View File

@ -89,6 +89,34 @@ void PacketStatistics::tick() {
} }
} }
void PacketStatistics::reset() {
std::lock_guard lock{this->data_mutex};
this->calculator_command.reset();
this->calculator_command_low.reset();
this->calculator_ack.reset();
this->calculator_ack_low.reset();
this->calculator_voice.reset();
this->calculator_voice_whisper.reset();
this->calculator_ping.reset();
}
void PacketStatistics::reset_offsets() {
std::lock_guard lock{this->data_mutex};
this->calculator_command.reset_offsets();
this->calculator_command_low.reset_offsets();
this->calculator_ack.reset_offsets();
this->calculator_ack_low.reset_offsets();
this->calculator_voice.reset_offsets();
this->calculator_voice_whisper.reset_offsets();
this->calculator_ping.reset_offsets();
}
float PacketStatistics::current_packet_loss() const { float PacketStatistics::current_packet_loss() const {
auto report = this->loss_report(); auto report = this->loss_report();
return report.total_loss(); return report.total_loss();

View File

@ -48,6 +48,8 @@ namespace ts::server::client {
void received_packet(protocol::PacketType /* type */, uint32_t /* packet id */); void received_packet(protocol::PacketType /* type */, uint32_t /* packet id */);
void tick(); void tick();
void reset();
void reset_offsets();
private: private:
std::chrono::system_clock::time_point last_short{}; std::chrono::system_clock::time_point last_short{};

View File

@ -1,50 +1,51 @@
#include "PrecomputedPuzzles.h" #include "./PrecomputedPuzzles.h"
#include "../../Configuration.h" #include "src/Configuration.h"
#include "../ConnectedClient.h"
#include <tomcrypt.h> #include <tomcrypt.h>
using namespace std; using namespace std;
using namespace ts; using namespace ts::server::udp;
using namespace ts::protocol;
PuzzleManager::PuzzleManager() {} PuzzleManager::PuzzleManager() = default;
PuzzleManager::~PuzzleManager() {} PuzzleManager::~PuzzleManager() = default;
size_t PuzzleManager::precomputedPuzzleCount() { return this->cached.size(); } size_t PuzzleManager::precomputed_puzzle_count() {
std::lock_guard lock{this->cache_lock};
bool PuzzleManager::precomputePuzzles(size_t limit) { return this->cached_puzzles.size();
while(precomputedPuzzleCount() < limit) generatePuzzle();
return true;
} }
std::shared_ptr<Puzzle> PuzzleManager::nextPuzzle() { bool PuzzleManager::precompute_puzzles(size_t amount) {
this->indexLock.lock(); std::random_device rd{};
size_t index = this->cacheIndex++ % this->cached.size(); std::mt19937 mt{rd()};
this->indexLock.unlock();
return this->cached[index]; amount = 5;
while(this->precomputed_puzzle_count() < amount)
this->generate_puzzle(mt);
return this->precomputed_puzzle_count() > 0;
} }
inline void rndNum(mp_int *result, int byteLength){ std::shared_ptr<Puzzle> PuzzleManager::next_puzzle() {
uint8_t buffer[byteLength]; std::lock_guard lock{this->cache_lock};
return this->cached_puzzles[this->cache_index++ % this->cached_puzzles.size()];
}
for(int index = 0; index < byteLength; index++) { inline void random_number(std::mt19937& generator, mp_int *result, int length){
int rnd = rand(); std::uniform_int_distribution<uint8_t> dist{};
uint8_t urnd = static_cast<uint8_t>(rnd & 0xFF);
buffer[index] = urnd; //TODO more secure!
} uint8_t buffer[length];
for(auto& byte : buffer)
byte = dist(generator);
mp_zero(result); mp_zero(result);
mp_read_unsigned_bin(result, buffer, byteLength); mp_read_unsigned_bin(result, buffer, length);
} }
inline bool solvePuzzle(Puzzle *puzzle){ inline bool solve_puzzle(Puzzle *puzzle) {
mp_int exp{}; mp_int exp{};
mp_init(&exp); mp_init(&exp);
mp_2expt(&exp, puzzle->level); mp_2expt(&exp, puzzle->level);
if (mp_exptmod(&puzzle->x, &exp, &puzzle->n, &puzzle->result) != CRYPT_OK) { //Sometimes it fails (unknow why :D) if (mp_exptmod(&puzzle->x, &exp, &puzzle->n, &puzzle->result) != CRYPT_OK) { //Sometimes it fails (unknown why :D)
mp_clear(&exp); mp_clear(&exp);
return false; return false;
} }
@ -66,17 +67,17 @@ inline bool write_bin_data(mp_int& data, uint8_t* result, size_t length) {
return true; return true;
} }
void PuzzleManager::generatePuzzle() { void PuzzleManager::generate_puzzle(std::mt19937& random_generator) {
auto puzzle = new Puzzle{}; auto puzzle = new Puzzle{};
puzzle->level = ts::config::voice::RsaPuzzleLevel;
mp_init_multi(&puzzle->x, &puzzle->n, &puzzle->result, nullptr); mp_init_multi(&puzzle->x, &puzzle->n, &puzzle->result, nullptr);
generate_new: generate_new:
rndNum(&puzzle->x, 64); random_number(random_generator, &puzzle->x, 64);
rndNum(&puzzle->n, 64); random_number(random_generator, &puzzle->n, 64);
puzzle->level = ts::config::voice::RsaPuzzleLevel;
if(!solvePuzzle(puzzle)) if(!solve_puzzle(puzzle))
goto generate_new; goto generate_new;
auto valid_x = mp_unsigned_bin_size(&puzzle->x) <= 64; auto valid_x = mp_unsigned_bin_size(&puzzle->x) <= 64;
@ -94,7 +95,7 @@ void PuzzleManager::generatePuzzle() {
if(!write_bin_data(puzzle->result, puzzle->data_result, 64)) if(!write_bin_data(puzzle->result, puzzle->data_result, 64))
goto generate_new; goto generate_new;
this->cached.push_back(shared_ptr<Puzzle>(puzzle, [](Puzzle* elm){ this->cached_puzzles.push_back(shared_ptr<Puzzle>(puzzle, [](Puzzle* elm){
mp_clear_multi(&elm->n, &elm->x, &elm->result, nullptr); mp_clear_multi(&elm->n, &elm->x, &elm->result, nullptr);
delete elm; delete elm;
})); }));

View File

@ -1,44 +1,39 @@
#pragma once #pragma once
#include <ThreadPool/Mutex.h>
#include <tommath.h> #include <tommath.h>
#include <memory> #include <memory>
#include <deque> #include <vector>
#include <misc/spin_lock.h>
#include <random>
namespace ts { namespace ts::server::udp {
namespace server { struct Puzzle {
class ConnectedClient; mp_int x;
} mp_int n;
int level;
namespace protocol { mp_int result;
struct Puzzle {
mp_int x;
mp_int n;
int level;
mp_int result; uint8_t data_x[64];
uint8_t data_n[64];
uint8_t data_result[64];
};
uint8_t data_x[64]; class PuzzleManager {
uint8_t data_n[64]; public:
uint8_t data_result[64]; PuzzleManager();
}; ~PuzzleManager();
class PuzzleManager {
public:
PuzzleManager();
~PuzzleManager();
bool precomputePuzzles(size_t limit); [[nodiscard]] bool precompute_puzzles(size_t amount);
size_t precomputedPuzzleCount(); [[nodiscard]] size_t precomputed_puzzle_count();
std::shared_ptr<Puzzle> nextPuzzle(); [[nodiscard]] std::shared_ptr<Puzzle> next_puzzle();
private: private:
void generatePuzzle(); void generate_puzzle(std::mt19937&);
threads::Mutex indexLock; size_t cache_index{0};
size_t cacheIndex = 0; spin_lock cache_lock{};
std::vector<std::shared_ptr<Puzzle>> cached_puzzles{};
std::deque<std::shared_ptr<Puzzle>> cached; };
};
}
} }

View File

@ -70,6 +70,7 @@ ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
this->connection->reset(); this->connection->reset();
this->connection->register_initiv_packet(); this->connection->register_initiv_packet();
this->connection->packet_statistics().reset_offsets();
this->crypto.protocol_encrypted = false; this->crypto.protocol_encrypted = false;
bool use_teaspeak = command.hasParm("teaspeak"); bool use_teaspeak = command.hasParm("teaspeak");

View File

@ -1,10 +1,8 @@
#include "POWHandler.h" #include "POWHandler.h"
#include "src/InstanceHandler.h" #include "src/InstanceHandler.h"
#include "src/VirtualServerManager.h"
#include "src/client/voice/VoiceClient.h" #include "src/client/voice/VoiceClient.h"
#include <misc/endianness.h> #include <misc/endianness.h>
#include <log/LogUtils.h> #include <log/LogUtils.h>
#include <src/client/voice/VoiceClient.h>
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -21,7 +19,7 @@ void POWHandler::execute_tick() {
lock_guard lock(this->pending_clients_lock); lock_guard lock(this->pending_clients_lock);
this->pending_clients.erase(remove_if(this->pending_clients.begin(), this->pending_clients.end(), [&, now](const shared_ptr<Client>& client) { this->pending_clients.erase(remove_if(this->pending_clients.begin(), this->pending_clients.end(), [&, now](const shared_ptr<Client>& client) {
if(now - client->last_packet > seconds(5)) { if(now - client->last_packet > std::chrono::seconds{5}) {
#ifdef POW_ERROR #ifdef POW_ERROR
if(client->state != LowHandshakeState::COMPLETED) { /* handshake succeeded */ if(client->state != LowHandshakeState::COMPLETED) { /* handshake succeeded */
debugMessage(this->get_server_id(), "[POW] Dropping connection from {} (Timeout)", net::to_string(client->address)); debugMessage(this->get_server_id(), "[POW] Dropping connection from {} (Timeout)", net::to_string(client->address));
@ -155,12 +153,6 @@ inline void generate_random(uint8_t *destination, size_t length) {
*(destination++) = (uint8_t) rand(); *(destination++) = (uint8_t) rand();
} }
inline void write_reversed(uint8_t* destination, uint8_t* source, size_t length) {
destination += length;
while(length-- > 0)
*(--destination) = *(source++);
}
void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler::Client> &client, const pipes::buffer_view &buffer) { void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler::Client> &client, const pipes::buffer_view &buffer) {
if(buffer.length() != 21) { if(buffer.length() != 21) {
#ifdef POW_ERROR #ifdef POW_ERROR
@ -172,7 +164,7 @@ void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler:
/* initialize data */ /* initialize data */
if(client->server_control_data[0] == 0) { if(client->server_control_data[0] == 0) {
generate_random(client->server_control_data, 16); generate_random(client->server_control_data, 16);
client->server_control_data[0] |= 1; client->server_control_data[0] |= 1U;
} }
/* parse values */ /* parse values */
@ -183,7 +175,7 @@ void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler:
uint8_t response_buffer[21]; uint8_t response_buffer[21];
response_buffer[0] = LowHandshakeState::COOKIE_SET; response_buffer[0] = LowHandshakeState::COOKIE_SET;
memcpy(&response_buffer[1], client->server_control_data, 16); memcpy(&response_buffer[1], client->server_control_data, 16);
write_reversed(&response_buffer[17], client->client_control_data, 4); *(uint32_t*) &response_buffer[17] = htonl(*(uint32_t*) &client->client_control_data);
this->send_data(client, pipes::buffer_view{response_buffer, 21}); this->send_data(client, pipes::buffer_view{response_buffer, 21});
} }
@ -211,7 +203,7 @@ void POWHandler::handle_puzzle_get(const std::shared_ptr<ts::server::POWHandler:
} }
if(!client->rsa_challenge) if(!client->rsa_challenge)
client->rsa_challenge = serverInstance->getVoiceServerManager()->rsaPuzzles()->nextPuzzle(); client->rsa_challenge = serverInstance->getVoiceServerManager()->rsaPuzzles()->next_puzzle();
/* send response */ /* send response */
{ {
@ -262,6 +254,7 @@ void POWHandler::handle_puzzle_solve(const std::shared_ptr<ts::server::POWHandle
#ifdef POW_ERROR #ifdef POW_ERROR
debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client", net::to_string(client->address)); debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client", net::to_string(client->address));
#endif #endif
client->rsa_challenge.reset(); /* get another RSA challenge */
this->reset_client(client); this->reset_client(client);
return; return;
} }

View File

@ -8,6 +8,7 @@
#include "VoiceServer.h" #include "VoiceServer.h"
#include "src/VirtualServer.h" #include "src/VirtualServer.h"
namespace ts::server { namespace ts::server {
class POWHandler { class POWHandler {
public: public:
@ -32,13 +33,13 @@ namespace ts::server {
std::chrono::system_clock::time_point last_packet; std::chrono::system_clock::time_point last_packet;
LowHandshakeState state = LowHandshakeState::COOKIE_GET; LowHandshakeState state = LowHandshakeState::COOKIE_GET;
uint8_t client_control_data[4] = {0,0,0,0}; uint8_t client_control_data[4]{0};
uint8_t server_control_data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; uint8_t server_control_data[16]{0};
uint8_t server_data[100]; uint8_t server_data[100];
uint32_t client_version; uint32_t client_version;
std::shared_ptr<protocol::Puzzle> rsa_challenge; std::shared_ptr<udp::Puzzle> rsa_challenge;
}; };
explicit POWHandler(VoiceServer* /* server */); explicit POWHandler(VoiceServer* /* server */);

View File

@ -6,6 +6,7 @@
#include <condition_variable> #include <condition_variable>
#include <pipes/buffer.h> #include <pipes/buffer.h>
#include <misc/spin_lock.h> #include <misc/spin_lock.h>
#include <ThreadPool/Mutex.h>
namespace ts { namespace ts {
namespace server { namespace server {

View File

@ -170,11 +170,11 @@ void VoiceServer::execute_resend(const std::chrono::system_clock::time_point &no
} }
for(auto& entry : buffers) for(auto& entry : buffers)
connection->packet_statistics().send_command((protocol::PacketType) entry->packet_type, entry->packet_id | entry->generation_id << 16U); connection->packet_statistics().send_command((protocol::PacketType) entry->packet_type, entry->packet_id | entry->generation_id << 16U);
if(buffers.size() > 0) //if(buffers.size() > 0)
logTrace(client->getServerId(), "{} Resending {} packets.", CLIENT_STR_LOG_PREFIX_(client), buffers.size()); // logTrace(client->getServerId(), "{} Resending {} packets.", CLIENT_STR_LOG_PREFIX_(client), buffers.size());
buffers.clear();
connection->triggerWrite(); connection->triggerWrite();
} }
buffers.clear();
} }
} }

2
shared

@ -1 +1 @@
Subproject commit e0eb4c5a16b900f6ed906c88a264d07479b13c5e Subproject commit ee7f26b7ed883027f0a81ece1c2aacd41053ce1e