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;
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->execute_loop = new event::EventExecutor("executor #");
//this->join_loop = new event::EventExecutor("joiner #");
@ -67,7 +67,8 @@ bool VirtualServerManager::initialize(bool autostart) {
this->state = State::STARTING;
logMessage(LOG_INSTANCE, "Generating server puzzles...");
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");
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);
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_executor_loop() { return this->execute_loop; }
@ -80,7 +80,7 @@ namespace ts {
InstanceHandler* handle;
threads::Mutex instanceLock;
std::deque<std::shared_ptr<VirtualServer>> instances;
protocol::PuzzleManager* puzzles = nullptr;
udp::PuzzleManager* puzzles{nullptr};
event::EventExecutor* execute_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);
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 ");

View File

@ -39,17 +39,21 @@ using namespace ts::token;
command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
CMD_REQ_SERVER;
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)))
return command_result{error::client_invalid_id, ""};
if (!client || (client.client != this && !this->isClientVisible(client.client, false)))
return command_result{error::client_invalid_id, ""};
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)) {
props.push_back(&prop.type());
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)) {
props.push_back(&prop.type());
}
this->notifyClientUpdated(client.client, props, false);
}
this->notifyClientUpdated(client.client, props, false);
if(client.client == this && this->getType() == ClientType::CLIENT_TEAMSPEAK)
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};
}

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 {
auto report = this->loss_report();
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 tick();
void reset();
void reset_offsets();
private:
std::chrono::system_clock::time_point last_short{};

View File

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

View File

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

View File

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

View File

@ -1,10 +1,8 @@
#include "POWHandler.h"
#include "src/InstanceHandler.h"
#include "src/VirtualServerManager.h"
#include "src/client/voice/VoiceClient.h"
#include <misc/endianness.h>
#include <log/LogUtils.h>
#include <src/client/voice/VoiceClient.h>
using namespace std;
using namespace std::chrono;
@ -21,7 +19,7 @@ void POWHandler::execute_tick() {
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) {
if(now - client->last_packet > seconds(5)) {
if(now - client->last_packet > std::chrono::seconds{5}) {
#ifdef POW_ERROR
if(client->state != LowHandshakeState::COMPLETED) { /* handshake succeeded */
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();
}
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) {
if(buffer.length() != 21) {
#ifdef POW_ERROR
@ -172,7 +164,7 @@ void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler:
/* initialize data */
if(client->server_control_data[0] == 0) {
generate_random(client->server_control_data, 16);
client->server_control_data[0] |= 1;
client->server_control_data[0] |= 1U;
}
/* parse values */
@ -183,7 +175,7 @@ void POWHandler::handle_cookie_get(const std::shared_ptr<ts::server::POWHandler:
uint8_t response_buffer[21];
response_buffer[0] = LowHandshakeState::COOKIE_SET;
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});
}
@ -211,7 +203,7 @@ void POWHandler::handle_puzzle_get(const std::shared_ptr<ts::server::POWHandler:
}
if(!client->rsa_challenge)
client->rsa_challenge = serverInstance->getVoiceServerManager()->rsaPuzzles()->nextPuzzle();
client->rsa_challenge = serverInstance->getVoiceServerManager()->rsaPuzzles()->next_puzzle();
/* send response */
{
@ -262,6 +254,7 @@ void POWHandler::handle_puzzle_solve(const std::shared_ptr<ts::server::POWHandle
#ifdef POW_ERROR
debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client", net::to_string(client->address));
#endif
client->rsa_challenge.reset(); /* get another RSA challenge */
this->reset_client(client);
return;
}

View File

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

View File

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

View File

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

2
shared

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