Fixed compile errors

This commit is contained in:
WolverinDEV 2020-02-02 21:54:37 +01:00
parent 3dcfad1038
commit 25173d5745
7 changed files with 464 additions and 417 deletions

View File

@ -15,8 +15,6 @@
#define MSG_DONTWAIT (0) #define MSG_DONTWAIT (0)
#else #else
#include <unistd.h> #include <unistd.h>
#include <unbound.h>
#include <unbound-event.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif

View File

@ -1,5 +1,5 @@
#ifdef WIN32 #ifdef WIN32
#include <WinSock2.h> #include <WinSock2.h>
#endif #endif
#include "ProtocolHandler.h" #include "ProtocolHandler.h"
@ -20,7 +20,7 @@ using namespace ts::protocol;
using namespace ts; using namespace ts;
ProtocolHandler::ProtocolHandler(ServerConnection* handle) : handle(handle) { ProtocolHandler::ProtocolHandler(ServerConnection* handle) : handle(handle) {
this->compression_handler.max_packet_size = 128 * 1024; /* max 128Kb */ this->compression_handler.max_packet_size = 128 * 1024; /* max 128Kb */
} }
ProtocolHandler::~ProtocolHandler() { ProtocolHandler::~ProtocolHandler() {
@ -28,514 +28,561 @@ ProtocolHandler::~ProtocolHandler() {
void ProtocolHandler::reset() { void ProtocolHandler::reset() {
this->server_type = server_type::UNKNOWN; this->server_type = server_type::UNKNOWN;
this->disconnect_id++; /* we've been resetted any pending disconnects are not from interest anymore */ this->disconnect_id++; /* we've been resetted any pending disconnects are not from interest anymore */
this->client_id = 0; this->client_id = 0;
this->acknowledge_handler.reset(); this->acknowledge_handler.reset();
this->connection_state = connection_state::INITIALIZING; this->connection_state = connection_state::INITIALIZING;
{ /* initialize pow handler */ { /* initialize pow handler */
this->pow.state = pow_state::COOKIE_SET; this->pow.state = pow_state::COOKIE_SET;
this->pow.last_buffer = pipes::buffer{}; this->pow.last_buffer = pipes::buffer{};
this->pow.last_resend = system_clock::time_point{}; this->pow.last_resend = system_clock::time_point{};
this->pow.last_response = system_clock::time_point{}; this->pow.last_response = system_clock::time_point{};
this->pow.client_control_data[0] = 0; /* clear set flag, so the client generates a new pack */ this->pow.client_control_data[0] = 0; /* clear set flag, so the client generates a new pack */
} }
{ {
this->crypto.alpha[0] = 0; this->crypto.alpha[0] = 0;
this->crypto.initiv_command = ""; this->crypto.initiv_command = "";
this->crypto.beta_length = 0; this->crypto.beta_length = 0;
if(this->crypto.identity.k) if(this->crypto.identity.k)
ecc_free(&this->crypto.identity); ecc_free(&this->crypto.identity);
memset(&this->crypto.identity, 0, sizeof(this->crypto.identity)); memset(&this->crypto.identity, 0, sizeof(this->crypto.identity));
} }
for(auto& buffer : this->_packet_buffers) { for(auto& buffer : this->_packet_buffers) {
lock_guard lock(buffer.buffer_lock); lock_guard lock(buffer.buffer_lock);
buffer.reset(); buffer.reset();
} }
this->_packet_id_manager.reset(); this->crypt_setupped = false;
this->crypt_handler.reset(); for(auto& calculator : this->incoming_generation_estimators)
calculator.reset();
this->_packet_id_manager.reset();
this->crypt_handler.reset();
this->ping.ping_received_timestamp = system_clock::time_point{}; this->ping.ping_received_timestamp = system_clock::time_point{};
} }
void ProtocolHandler::connect() { void ProtocolHandler::connect() {
this->connection_state = connection_state::INIT_LOW; this->connection_state = connection_state::INIT_LOW;
this->connect_timestamp = system_clock::now(); this->connect_timestamp = system_clock::now();
this->pow_send_cookie_get(); this->pow_send_cookie_get();
{ {
auto command = this->generate_client_initiv(); auto command = this->generate_client_initiv();
auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{command.data(), command.size()}); auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{command.data(), command.size()});
packet->enable_flag(PacketFlag::NewProtocol); packet->enable_flag(PacketFlag::NewProtocol);
this->send_packet(packet); this->send_packet(packet);
} }
} }
void ProtocolHandler::execute_tick() { void ProtocolHandler::execute_tick() {
auto now = system_clock::now(); auto now = system_clock::now();
if(this->connection_state < connection_state::DISCONNECTED) { if(this->connection_state < connection_state::DISCONNECTED) {
if(!this->pow.last_buffer.empty() && this->pow.last_resend < now - seconds(1)) { if(!this->pow.last_buffer.empty() && this->pow.last_resend < now - seconds(1)) {
this->pow.last_resend = now; this->pow.last_resend = now;
this->send_packet(make_shared<ClientPacket>(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer)); this->send_packet(make_shared<ClientPacket>(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer));
} }
if(this->connection_state == connection_state::INIT_LOW || this->connection_state == connection_state::INIT_HIGH) { if(this->connection_state == connection_state::INIT_LOW || this->connection_state == connection_state::INIT_HIGH) {
if(this->connect_timestamp < now - seconds(15)) { if(this->connect_timestamp < now - seconds(15)) {
this->handle->call_connect_result.call(this->handle->errors.register_error("timeout (" + to_string(this->connection_state) + ")"), true); this->handle->call_connect_result.call(this->handle->errors.register_error("timeout (" + to_string(this->connection_state) + ")"), true);
this->handle->close_connection(); this->handle->close_connection();
return; return;
} }
} }
if(this->connection_state == connection_state::DISCONNECTING) { if(this->connection_state == connection_state::DISCONNECTING) {
if(this->disconnect_timestamp < now - seconds(5)) { /* disconnect timeout */ if(this->disconnect_timestamp < now - seconds(5)) { /* disconnect timeout */
this->handle->close_connection(); this->handle->close_connection();
return; return;
} }
} }
this->execute_resend(); this->execute_resend();
/* ping */ /* ping */
if(this->connection_state == connection_state::CONNECTED) { if(this->connection_state == connection_state::CONNECTED) {
if(this->ping.ping_send_timestamp + seconds(1) < now) if(this->ping.ping_send_timestamp + seconds(1) < now)
this->ping_send_request(); this->ping_send_request();
if(this->ping.ping_received_timestamp.time_since_epoch().count() > 0) { if(this->ping.ping_received_timestamp.time_since_epoch().count() > 0) {
if(now - this->ping.ping_received_timestamp > seconds(30)) { if(now - this->ping.ping_received_timestamp > seconds(30)) {
this->handle->execute_callback_disconnect.call(tr("ping timeout"), true); this->handle->execute_callback_disconnect.call(tr("ping timeout"), true);
this->handle->close_connection(); this->handle->close_connection();
return; return;
} }
} else } else
this->ping.ping_received_timestamp = now; this->ping.ping_received_timestamp = now;
} }
} }
} }
void ProtocolHandler::execute_resend() { void ProtocolHandler::execute_resend() {
if(this->connection_state >= connection_state::DISCONNECTED) if(this->connection_state >= connection_state::DISCONNECTED)
return; return;
deque<pipes::buffer> buffers; deque<pipes::buffer> buffers;
auto now = system_clock::now(); auto now = system_clock::now();
system_clock::time_point next = now + seconds(5); /* in real we're doing it all 500ms */ system_clock::time_point next = now + seconds(5); /* in real we're doing it all 500ms */
string error; string error;
auto resended = this->acknowledge_handler.execute_resend(now, next, buffers, error); auto resended = this->acknowledge_handler.execute_resend(now, next, buffers, error);
if(resended < 0) { if(resended < 0) {
log_error(category::connection, tr("Failed to receive acknowledge: {}"), error); log_error(category::connection, tr("Failed to receive acknowledge: {}"), error);
this->handle->execute_callback_disconnect(tr("packet resend failed")); this->handle->execute_callback_disconnect(tr("packet resend failed"));
this->handle->close_connection(); this->handle->close_connection();
return; return;
} }
auto socket = this->handle->get_socket(); auto socket = this->handle->get_socket();
if(socket) { if(socket) {
for(const auto& buffer : buffers) for(const auto& buffer : buffers)
socket->send_message(buffer); socket->send_message(buffer);
} }
this->handle->schedule_resend(next); this->handle->schedule_resend(next);
} }
void ProtocolHandler::progress_packet(const pipes::buffer_view &buffer) { void ProtocolHandler::progress_packet(const pipes::buffer_view &buffer) {
if(this->connection_state >= connection_state::DISCONNECTED) { if(this->connection_state >= connection_state::DISCONNECTED) {
log_warn(category::connection, tr("Dropping received packet. We're already disconnected.")); log_warn(category::connection, tr("Dropping received packet. We're already disconnected."));
return; return;
} }
if(buffer.length() < ServerPacket::META_SIZE) { if(buffer.length() < ServerPacket::META_SIZE) {
log_error(category::connection, tr("Received a packet which is too small. ({})"), buffer.length()); log_error(category::connection, tr("Received a packet which is too small. ({})"), buffer.length());
return; return;
} }
auto packet = std::shared_ptr<ts::protocol::ServerPacket>(ts::protocol::ServerPacket::from_buffer(buffer).release()); auto packet = std::shared_ptr<ts::protocol::ServerPacket>(ts::protocol::ServerPacket::from_buffer(buffer).release());
auto packet_type = packet->type(); auto packet_type = packet->type();
auto packet_id = packet->packetId(); auto packet_id = packet->packetId();
auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW; auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW;
/* special handling */ /* special handling */
if(packet_type.type() == protocol::INIT1) { if(packet_type.type() == protocol::INIT1) {
this->handlePacketInit(packet); this->handlePacketInit(packet);
return; return;
} }
if(packet_type.type() < 0 || packet_type.type() >= this->_packet_buffers.size()) { if(packet_type.type() < 0 || packet_type.type() >= this->_packet_buffers.size()) {
log_error(category::connection, tr("Received packet with invalid type. ({})"), packet_type.type()); log_error(category::connection, tr("Received packet with invalid type. ({})"), packet_type.type());
return; return;
} }
auto& read_queue = this->_packet_buffers[packet_type.type()]; auto& read_queue = this->_packet_buffers[packet_type.type()];
packet->generationId(read_queue.generation(packet_id)); auto& gen_calc = this->incoming_generation_estimators[packet_type.type()];
packet->generationId(gen_calc.visit_packet(packet_id));
auto gen = packet->generationId();
if(ordered) {
unique_lock queue_lock(read_queue.buffer_lock);
auto result = read_queue.accept_index(packet_id);
if(result != 0) { /* packet index is ahead buffer index */
log_error(category::connection, tr("Failed to verify command packet: {} (Index: {} Current index: {})"), result, packet_id, read_queue.current_index());
if(ordered) { if(result == -1) { /* underflow */
unique_lock queue_lock(read_queue.buffer_lock); /* we've already got the packet, but the client dosn't know that so we've to send the acknowledge again */
auto result = read_queue.accept_index(packet_id); if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow)
if(result != 0) { /* packet index is ahead buffer index */ this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow);
log_error(category::connection, tr("Failed to verify command packet: {} (Index: {} Current index: {})"), result, packet_id, read_queue.current_index()); }
return;
}
}
if(result == -1) { /* underflow */ packet->setEncrypted(!packet->has_flag(PacketFlag::Unencrypted));
/* we've already got the packet, but the client dosn't know that so we've to send the acknowledge again */ if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow) packet->setCompressed(packet->has_flag(PacketFlag::Compressed));
this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow); }
} //NOTICE I found out that the Compressed flag is set if the packet contains an audio header
return;
}
}
packet->setEncrypted(!packet->has_flag(PacketFlag::Unencrypted)); if(packet->isEncrypted()) {
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ std::string error;
packet->setCompressed(packet->has_flag(PacketFlag::Compressed));
}
//NOTICE I found out that the Compressed flag is set if the packet contains an audio header
string error = "success"; ts::connection::CryptHandler::key_t crypt_key{};
if(!this->crypt_handler.progressPacketIn(packet.get(), error, false)){ ts::connection::CryptHandler::nonce_t crypt_nonce{};
if(!this->crypt_handler.use_default()) {
if(!this->crypt_handler.progressPacketIn(packet.get(), error, true)){
log_error(category::connection, tr("Failed to decrypt packet ({}), even with default key: {}"), packet_type.name(), error);
return;
} else {
log_error(category::connection, tr("Successfully decrypt packet ({} | {}) with default key."), packet_type.name(), packet_id);
//FIXME Test if we're in init high
}
} else {
log_error(category::connection, tr("Failed to decrypt packet ({}) with default key: {}"), packet_type.name(), error);
return;
}
}
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ bool decrypt_result;
if(packet->has_flag(PacketFlag::Unencrypted)) {
log_warn(category::connection, tr("Received unencrypted command packet! Dropping packet."));
return;
}
}
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow) if(!this->crypt_setupped) {
this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow); crypt_key = ts::connection::CryptHandler::default_key;
crypt_nonce = ts::connection::CryptHandler::default_nonce;
} else {
if(!this->crypt_handler.generate_key_nonce(false, packet_type.type(), packet->packetId(), packet->generationId(), crypt_key, crypt_nonce)) {
log_error(category::connection, tr("Failed to generate crypt key/nonce. This should never happen! Dropping packet."));
return;
}
}
{ auto mac_ptr = packet->mac().data_ptr<void>();
unique_lock queue_lock(read_queue.buffer_lock); auto header_ptr = packet->header().data_ptr<void>();
auto data_ptr = packet->data().data_ptr<void>();
decrypt_result = this->crypt_handler.decrypt(
header_ptr, packet->header_length(),
data_ptr, packet->data_length(),
mac_ptr,
crypt_key, crypt_nonce,
error
);
if(ordered) { /* ordered */ if(!decrypt_result) {
if(!read_queue.insert_index(packet_id, std::forward<shared_ptr<ServerPacket>>(packet))) { if(!this->crypt_setupped)
log_warn(category::connection, tr("Failed to insert ordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id); log_error(category::connection, tr("Failed to decrypt packet ({}), with default key."), packet_type.name());
} else
} else { log_trace(category::connection, tr("Failed to decrypt packet {}."), packet_type.name());
if(!read_queue.push_back(std::forward<shared_ptr<ServerPacket>>(packet))) { return;
log_warn(category::connection, tr("Failed to insert unordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id); }
/* return; dont stop here because we've to progress the packets */ }
} else {
read_queue.index_set(packet_id); /* may we've skipped one packet id */
}
}
}
while(this->handle_packets()); if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){
if(packet->has_flag(PacketFlag::Unencrypted)) {
log_warn(category::connection, tr("Received unencrypted command packet! Dropping packet."));
return;
}
}
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow)
this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow);
{
unique_lock queue_lock(read_queue.buffer_lock);
if(ordered) { /* ordered */
if(!read_queue.insert_index(packet_id, std::forward<shared_ptr<ServerPacket>>(packet))) {
log_warn(category::connection, tr("Failed to insert ordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id);
}
} else {
if(!read_queue.push_back(std::forward<shared_ptr<ServerPacket>>(packet))) {
log_warn(category::connection, tr("Failed to insert unordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id);
/* return; dont stop here because we've to progress the packets */
} else {
read_queue.index_set(packet_id); /* may we've skipped one packet id */
}
}
}
while(this->handle_packets());
} }
bool ProtocolHandler::handle_packets() { bool ProtocolHandler::handle_packets() {
if(this->connection_state >= connection_state::DISCONNECTED) { if(this->connection_state >= connection_state::DISCONNECTED) {
log_warn(category::connection, tr("Don't handle received packets because we're already disconnected.")); log_warn(category::connection, tr("Don't handle received packets because we're already disconnected."));
return false; return false;
} }
bool reexecute_handle = false; bool reexecute_handle = false;
shared_ptr<ServerPacket> current_packet = nullptr; shared_ptr<ServerPacket> current_packet = nullptr;
packet_buffer_t* buffer = nullptr; packet_buffer_t* buffer = nullptr;
unique_lock<std::recursive_timed_mutex> buffer_lock; unique_lock<std::recursive_timed_mutex> buffer_lock;
unique_lock<std::recursive_timed_mutex> buffer_execute_lock; unique_lock<std::recursive_timed_mutex> buffer_execute_lock;
std::string error = "success"; std::string error = "success";
{ {
auto base_index = this->_packet_buffers_index; auto base_index = this->_packet_buffers_index;
auto select_index = base_index; auto select_index = base_index;
auto max_index = this->_packet_buffers.size(); auto max_index = this->_packet_buffers.size();
for(size_t index = 0; index < max_index; index++) { for(size_t index = 0; index < max_index; index++) {
if(!buffer) select_index++; if(!buffer) select_index++;
auto& buf = this->_packet_buffers[base_index++ % max_index]; auto& buf = this->_packet_buffers[base_index++ % max_index];
unique_lock ring_lock(buf.buffer_lock, try_to_lock); unique_lock ring_lock(buf.buffer_lock, try_to_lock);
if(!ring_lock.owns_lock()) { if(!ring_lock.owns_lock()) {
log_debug(category::connection, tr("Skipping packet type {} for handling"), base_index++ % max_index); log_debug(category::connection, tr("Skipping packet type {} for handling"), base_index++ % max_index);
continue; continue;
} }
if(buf.front_set()) { if(buf.front_set()) {
if(!buffer) { /* lets still test for reexecute */ if(!buffer) { /* lets still test for reexecute */
buffer_execute_lock = unique_lock(buf.execute_lock, try_to_lock); buffer_execute_lock = unique_lock(buf.execute_lock, try_to_lock);
if(!buffer_execute_lock.owns_lock()) { if(!buffer_execute_lock.owns_lock()) {
log_debug(category::connection, tr("Skipping packet type {} for handling (already executed)"), base_index++ % max_index); log_debug(category::connection, tr("Skipping packet type {} for handling (already executed)"), base_index++ % max_index);
continue; continue;
} }
buffer_lock = move(ring_lock); buffer_lock = move(ring_lock);
buffer = &buf; buffer = &buf;
} else { } else {
reexecute_handle |= true; reexecute_handle |= true;
break; break;
} }
} }
} }
this->_packet_buffers_index = select_index % max_index; /* garante that we will not hangup with commands! */ this->_packet_buffers_index = select_index % max_index; /* garante that we will not hangup with commands! */
} }
if(buffer){ if(buffer){
uint16_t sequence_length = 0; uint16_t sequence_length = 0;
current_packet = buffer->slot_value(sequence_length++); current_packet = buffer->slot_value(sequence_length++);
if(current_packet) { if(current_packet) {
if((current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow) && current_packet->has_flag(PacketFlag::Fragmented)) { if((current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow) && current_packet->has_flag(PacketFlag::Fragmented)) {
do { do {
if(sequence_length >= buffer->capacity()) { if(sequence_length >= buffer->capacity()) {
log_warn(category::connection, tr("Received fragmented packets which have a too long order. Dropping queue, which will cause a client drop.")); log_warn(category::connection, tr("Received fragmented packets which have a too long order. Dropping queue, which will cause a client drop."));
buffer->clear(); buffer->clear();
return false; return false;
} }
current_packet = buffer->slot_value(sequence_length++); current_packet = buffer->slot_value(sequence_length++);
} while(current_packet && !current_packet->has_flag(PacketFlag::Fragmented)); } while(current_packet && !current_packet->has_flag(PacketFlag::Fragmented));
} }
} else { } else {
log_critical(category::connection, tr("buffer->slot_value(sequence_length++) returned nullptr!")); log_critical(category::connection, tr("buffer->slot_value(sequence_length++) returned nullptr!"));
//FIXME! //FIXME!
//logCritical(this->client->getServer()->getServerId(), "buffer->slot_value(sequence_length++) returned nullptr!") //logCritical(this->client->getServer()->getServerId(), "buffer->slot_value(sequence_length++) returned nullptr!")
}; };
if(current_packet) { //We could reconstruct a new packet! if(current_packet) { //We could reconstruct a new packet!
if(sequence_length > 1) { //We have to merge if(sequence_length > 1) { //We have to merge
vector<pipes::buffer> append; vector<pipes::buffer> append;
append.reserve(sequence_length - 1); append.reserve(sequence_length - 1);
uint16_t packet_count = 0; uint16_t packet_count = 0;
current_packet = buffer->pop_front(); current_packet = buffer->pop_front();
packet_count++; packet_count++;
do { do {
auto packet = buffer->pop_front(); auto packet = buffer->pop_front();
packet_count++; packet_count++;
if(!packet) { if(!packet) {
log_critical(category::connection, tr("readQueue->peekNext(seqIndex++) => nullptr_t!")); log_critical(category::connection, tr("readQueue->peekNext(seqIndex++) => nullptr_t!"));
return false; return false;
} }
append.push_back(packet->data()); append.push_back(packet->data());
if(packet->has_flag(PacketFlag::Fragmented)) break; if(packet->has_flag(PacketFlag::Fragmented)) break;
} while(packet_count < sequence_length); } while(packet_count < sequence_length);
if(packet_count != sequence_length) { if(packet_count != sequence_length) {
log_critical(category::connection, tr("seqIndex != index failed! seqIndex: {} seqLength: {} This may cause a application crash!"), packet_count, sequence_length); log_critical(category::connection, tr("seqIndex != index failed! seqIndex: {} seqLength: {} This may cause a application crash!"), packet_count, sequence_length);
sequence_length = packet_count; sequence_length = packet_count;
current_packet = nullptr; current_packet = nullptr;
} else { } else {
current_packet->append_data(append); current_packet->append_data(append);
} }
} else { } else {
if(buffer->pop_front() != current_packet) { if(buffer->pop_front() != current_packet) {
log_critical(category::connection, tr("buffer->pop_front() != current_packet failed.")); log_critical(category::connection, tr("buffer->pop_front() != current_packet failed."));
} }
} }
reexecute_handle |= buffer->front_set(); reexecute_handle |= buffer->front_set();
buffer_lock.unlock(); //We got our packet so release it buffer_lock.unlock(); //We got our packet so release it
if(current_packet) { if(current_packet) {
if(!this->compression_handler.progressPacketIn(current_packet.get(), error)) { if(!this->compression_handler.progressPacketIn(current_packet.get(), error)) {
log_error(category::connection, tr("Failed to decompress received packet. Error: {}"), error); log_error(category::connection, tr("Failed to decompress received packet. Error: {}"), error);
current_packet = nullptr; current_packet = nullptr;
} }
} }
} }
} }
if(current_packet){ if(current_packet){
auto startTime = chrono::system_clock::now(); auto startTime = chrono::system_clock::now();
try { try {
if(current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow) if(current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow)
this->handlePacketCommand(current_packet); this->handlePacketCommand(current_packet);
else if(current_packet->type() == PacketTypeInfo::Ack || current_packet->type() == PacketTypeInfo::AckLow) else if(current_packet->type() == PacketTypeInfo::Ack || current_packet->type() == PacketTypeInfo::AckLow)
this->handlePacketAck(current_packet); this->handlePacketAck(current_packet);
else if(current_packet->type() == PacketTypeInfo::Voice || current_packet->type() == PacketTypeInfo::VoiceWhisper) else if(current_packet->type() == PacketTypeInfo::Voice || current_packet->type() == PacketTypeInfo::VoiceWhisper)
this->handlePacketVoice(current_packet); this->handlePacketVoice(current_packet);
else if(current_packet->type() == PacketTypeInfo::Ping || current_packet->type() == PacketTypeInfo::Pong) else if(current_packet->type() == PacketTypeInfo::Ping || current_packet->type() == PacketTypeInfo::Pong)
this->handlePacketPing(current_packet); this->handlePacketPing(current_packet);
} catch (std::exception& ex) { } catch (std::exception& ex) {
log_critical(category::connection, tr("Exception reached root tree! {}"), ex.what()); log_critical(category::connection, tr("Exception reached root tree! {}"), ex.what());
} }
auto end = chrono::system_clock::now(); auto end = chrono::system_clock::now();
if(end - startTime > chrono::milliseconds(5)) { if(end - startTime > chrono::milliseconds(5)) {
if(current_packet->type() != PacketTypeInfo::Command && current_packet->type() != PacketTypeInfo::CommandLow) { if(current_packet->type() != PacketTypeInfo::Command && current_packet->type() != PacketTypeInfo::CommandLow) {
log_warn(category::connection, log_warn(category::connection,
tr("Handling of packet {} ({}) needed longer than expected. Handle time {}ms"), tr("Handling of packet {} ({}) needed longer than expected. Handle time {}ms"),
current_packet->packetId(), current_packet->type().name(), duration_cast<milliseconds>(end - startTime).count()); current_packet->packetId(), current_packet->type().name(), duration_cast<milliseconds>(end - startTime).count());
} }
} }
} }
if(buffer_execute_lock.owns_lock()) if(buffer_execute_lock.owns_lock())
buffer_execute_lock.unlock(); buffer_execute_lock.unlock();
return reexecute_handle; return reexecute_handle;
} }
bool ProtocolHandler::create_datagram_packets(std::vector<pipes::buffer> &result, const std::shared_ptr<ts::protocol::ClientPacket> &packet) { bool ProtocolHandler::create_datagram_packets(std::vector<pipes::buffer> &result, const std::shared_ptr<ts::protocol::ClientPacket> &packet) {
string error = "success"; string error = "success";
if(packet->type().compressable() && !packet->memory_state.fragment_entry) { if(packet->type().compressable() && !packet->memory_state.fragment_entry) {
packet->enable_flag(PacketFlag::Compressed); packet->enable_flag(PacketFlag::Compressed);
if(!this->compression_handler.progressPacketOut(packet.get(), error)) { if(!this->compression_handler.progressPacketOut(packet.get(), error)) {
log_error(category::connection, tr("Could not compress outgoing packet.\nThis could cause fatal failed for the client.\nError: {}"), error); log_error(category::connection, tr("Could not compress outgoing packet.\nThis could cause fatal failed for the client.\nError: {}"), error);
return false; return false;
} }
} }
if(packet->data().length() > packet->type().max_length()){ if(packet->data().length() > packet->type().max_length()){
if(!packet->type().fragmentable()) { if(!packet->type().fragmentable()) {
log_error(category::connection, tr("We've tried to send a too long, not fragmentable packet. Dropping packet of type {} with length {}"), packet->type().name(), packet->data().length()); log_error(category::connection, tr("We've tried to send a too long, not fragmentable packet. Dropping packet of type {} with length {}"), packet->type().name(), packet->data().length());
return false; return false;
} }
std::vector<shared_ptr<ClientPacket>> siblings; std::vector<shared_ptr<ClientPacket>> siblings;
siblings.reserve(8); siblings.reserve(8);
{ //Split packets { //Split packets
auto buffer = packet->data(); auto buffer = packet->data();
const auto max_length = packet->type().max_length(); const auto max_length = packet->type().max_length();
while(buffer.length() > max_length * 2) { while(buffer.length() > max_length * 2) {
siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer.view(0, max_length).dup(ts::buffer::allocate_buffer(max_length)))); siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer.view(0, max_length).dup(ts::buffer::allocate_buffer(max_length))));
buffer = buffer.range(max_length); buffer = buffer.range(max_length);
} }
if(buffer.length() > max_length) { //Divide rest by 2 if(buffer.length() > max_length) { //Divide rest by 2
siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer.view(0, buffer.length() / 2).dup(ts::buffer::allocate_buffer(buffer.length() / 2)))); siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer.view(0, buffer.length() / 2).dup(ts::buffer::allocate_buffer(buffer.length() / 2))));
buffer = buffer.range(buffer.length() / 2); buffer = buffer.range(buffer.length() / 2);
} }
siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer)); siblings.push_back(make_shared<ClientPacket>(packet->type(), buffer));
for(const auto& frag : siblings) { for(const auto& frag : siblings) {
frag->setFragmentedEntry(true); frag->setFragmentedEntry(true);
frag->enable_flag(PacketFlag::NewProtocol); frag->enable_flag(PacketFlag::NewProtocol);
} }
} }
assert(siblings.size() >= 2); assert(siblings.size() >= 2);
siblings.front()->enable_flag(PacketFlag::Fragmented); siblings.front()->enable_flag(PacketFlag::Fragmented);
if(packet->has_flag(PacketFlag::Compressed)) if(packet->has_flag(PacketFlag::Compressed))
siblings.front()->enable_flag(PacketFlag::Compressed); siblings.front()->enable_flag(PacketFlag::Compressed);
siblings.back()->enable_flag(PacketFlag::Fragmented); siblings.back()->enable_flag(PacketFlag::Fragmented);
if(packet->getListener()) if(packet->getListener())
siblings.back()->setListener(std::move(packet->getListener())); //Move the listener to the last :) siblings.back()->setListener(std::move(packet->getListener())); //Move the listener to the last :)
result.reserve(siblings.size()); result.reserve(siblings.size());
for(const auto& frag : siblings) for(const auto& frag : siblings)
create_datagram_packets(result, frag); create_datagram_packets(result, frag);
return true; return true;
} }
if(!packet->memory_state.id_branded) { if(!packet->memory_state.id_branded) {
packet->clientId(this->client_id); packet->clientId(this->client_id);
if(packet->type().type() == PacketType::INIT1) { if(packet->type().type() == PacketType::INIT1) {
packet->applyPacketId(101, 0); packet->applyPacketId(101, 0);
} else { } else {
packet->applyPacketId(this->_packet_id_manager); packet->applyPacketId(this->_packet_id_manager);
} }
//log_trace(category::connection, tr("Packet {} got packet id {}"), packet->type().name(), packet->packetId()); //log_trace(category::connection, tr("Packet {} got packet id {}"), packet->type().name(), packet->packetId());
} }
if(!this->crypt_handler.progressPacketOut(packet.get(), error, false)) {
log_error(category::connection, tr("Failed to encrypt packet: {}"), error);
return false;
}
/* if(packet->has_flag(PacketFlag::Unencrypted)) {
this->crypt_handler.write_default_mac(packet->mac().data_ptr());
} else {
ts::connection::CryptHandler::key_t crypt_key{};
ts::connection::CryptHandler::nonce_t crypt_nonce{};
if(!this->crypt_setupped) {
crypt_key = ts::connection::CryptHandler::default_key;
crypt_nonce = ts::connection::CryptHandler::default_nonce;
} else {
if(!this->crypt_handler.generate_key_nonce(true, packet->type().type(), packet->packetId(), packet->generationId(), crypt_key, crypt_nonce)) {
log_error(category::connection, tr("Failed to generate crypt key/nonce. Dropping packet"), error);
return false;
}
}
auto crypt_result = this->crypt_handler.encrypt(packet->header().data_ptr(), packet->header().length(),
packet->data().data_ptr(), packet->data().length(),
packet->mac().data_ptr(),
crypt_key, crypt_nonce, error);
if(!crypt_result){
log_error(category::connection, tr("Failed to encrypt packet: {}"), error);
return false;
}
}
/*
#ifndef CONNECTION_NO_STATISTICS #ifndef CONNECTION_NO_STATISTICS
if(this->client && this->client->getServer()) if(this->client && this->client->getServer())
this->client->connectionStatistics->logOutgoingPacket(packet); this->client->connectionStatistics->logOutgoingPacket(packet);
#endif #endif
*/ */
result.push_back(packet->buffer()); result.push_back(packet->buffer());
this->acknowledge_handler.process_packet(*packet); this->acknowledge_handler.process_packet(*packet);
return true; return true;
} }
void ProtocolHandler::send_command(const ts::Command &cmd, const std::function<void(bool)> &ack_callback) { void ProtocolHandler::send_command(const ts::Command &cmd, const std::function<void(bool)> &ack_callback) {
auto data = cmd.build(); auto data = cmd.build();
auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()}); auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()});
if(ack_callback) { if(ack_callback) {
auto begin = chrono::system_clock::now(); auto begin = chrono::system_clock::now();
packet->setListener(make_unique<threads::Future<bool>>()); packet->setListener(make_unique<threads::Future<bool>>());
packet->getListener()->waitAndGetLater([ack_callback, begin](bool f) { packet->getListener()->waitAndGetLater([ack_callback, begin](bool f) {
auto end = chrono::system_clock::now(); auto end = chrono::system_clock::now();
if(ack_callback) if(ack_callback)
ack_callback(f); ack_callback(f);
log_trace(category::connection, tr("Time needed for command: {}"), chrono::duration_cast<chrono::milliseconds>(end - begin).count()); log_trace(category::connection, tr("Time needed for command: {}"), chrono::duration_cast<chrono::milliseconds>(end - begin).count());
}); });
} }
packet->enable_flag(PacketFlag::NewProtocol); packet->enable_flag(PacketFlag::NewProtocol);
this->send_packet(packet); this->send_packet(packet);
} }
void ProtocolHandler::send_packet(const std::shared_ptr<ts::protocol::ClientPacket> &packet) { void ProtocolHandler::send_packet(const std::shared_ptr<ts::protocol::ClientPacket> &packet) {
std::vector<pipes::buffer> result; std::vector<pipes::buffer> result;
if(!this->create_datagram_packets(result, packet) || result.empty()) { if(!this->create_datagram_packets(result, packet) || result.empty()) {
log_error(category::connection, tr("Failed to create datagram packets!")); log_error(category::connection, tr("Failed to create datagram packets!"));
return; return;
} }
auto socket = this->handle->get_socket(); auto socket = this->handle->get_socket();
if(!socket) { if(!socket) {
log_error(category::connection, tr("Failed to get socket!")); log_error(category::connection, tr("Failed to get socket!"));
return; return;
} }
for(const auto& buffer : result) for(const auto& buffer : result)
socket->send_message(buffer); socket->send_message(buffer);
} }
void ProtocolHandler::send_acknowledge(uint16_t packet_id, bool low) { void ProtocolHandler::send_acknowledge(uint16_t packet_id, bool low) {
char buffer[2]; char buffer[2];
le2be16(packet_id, buffer); le2be16(packet_id, buffer);
auto packet = make_shared<protocol::ClientPacket>(low ? protocol::PacketTypeInfo::AckLow : protocol::PacketTypeInfo::Ack, 0, pipes::buffer_view{buffer, 2}); auto packet = make_shared<protocol::ClientPacket>(low ? protocol::PacketTypeInfo::AckLow : protocol::PacketTypeInfo::Ack, 0, pipes::buffer_view{buffer, 2});
if(this->connection_state >= connection_state::CONNECTING) { if(this->connection_state >= connection_state::CONNECTING) {
;//packet->toggle(protocol::PacketFlag::NewProtocol, !low); ;//packet->toggle(protocol::PacketFlag::NewProtocol, !low);
//LivingBots DDOS protection dont want a new protocol here! //LivingBots DDOS protection dont want a new protocol here!
} }
this->send_packet(packet); this->send_packet(packet);
} }
void ProtocolHandler::do_close_connection() { void ProtocolHandler::do_close_connection() {
this->connection_state = connection_state::DISCONNECTED; this->connection_state = connection_state::DISCONNECTED;
for(auto& buffer : this->_packet_buffers) { for(auto& buffer : this->_packet_buffers) {
lock_guard lock(buffer.buffer_lock); lock_guard lock(buffer.buffer_lock);
buffer.clear(); buffer.clear();
} }
} }
void ProtocolHandler::disconnect(const std::string &reason) { void ProtocolHandler::disconnect(const std::string &reason) {
if(this->connection_state >= connection_state::DISCONNECTING) if(this->connection_state >= connection_state::DISCONNECTING)
return; return;
this->connection_state = connection_state::DISCONNECTING; this->connection_state = connection_state::DISCONNECTING;
this->disconnect_timestamp = system_clock::now(); this->disconnect_timestamp = system_clock::now();
auto did = ++this->disconnect_id; auto did = ++this->disconnect_id;
Command cmd("clientdisconnect"); Command cmd("clientdisconnect");
cmd["reasonmsg"] = reason; cmd["reasonmsg"] = reason;
this->send_command(cmd, [&, did](bool success){ this->send_command(cmd, [&, did](bool success){
/* if !success then we'll have prop already triggered the timeout and this here is obsolete */ /* if !success then we'll have prop already triggered the timeout and this here is obsolete */
if(success && this->connection_state == connection_state::DISCONNECTING && this->disconnect_id == did) if(success && this->connection_state == connection_state::DISCONNECTING && this->disconnect_id == did)
this->handle->close_connection(); this->handle->close_connection();
}); });
} }

View File

@ -10,9 +10,10 @@
#include <protocol/ringbuffer.h> #include <protocol/ringbuffer.h>
#include <protocol/Packet.h> #include <protocol/Packet.h>
#include <protocol/CryptionHandler.h> #include <protocol/CryptHandler.h>
#include <protocol/CompressionHandler.h> #include <protocol/CompressionHandler.h>
#include <protocol/AcknowledgeManager.h> #include <protocol/AcknowledgeManager.h>
#include <protocol/generation.h>
#include "ServerConnection.h" #include "ServerConnection.h"
namespace ts { namespace ts {
@ -124,9 +125,11 @@ namespace tc {
uint16_t client_id = 0; uint16_t client_id = 0;
ts::protocol::PacketIdManager _packet_id_manager; ts::protocol::PacketIdManager _packet_id_manager;
packet_buffers_t _packet_buffers; packet_buffers_t _packet_buffers;
std::array<ts::protocol::generation_estimator, 9> incoming_generation_estimators{}; /* implementation is thread save */
uint8_t _packet_buffers_index = 0; uint8_t _packet_buffers_index = 0;
ts::connection::CryptionHandler crypt_handler; bool crypt_setupped{false};
ts::connection::CryptHandler crypt_handler;
ts::connection::CompressionHandler compression_handler; ts::connection::CompressionHandler compression_handler;
ts::connection::AcknowledgeManager acknowledge_handler; ts::connection::AcknowledgeManager acknowledge_handler;

View File

@ -1,8 +1,6 @@
#include "ProtocolHandler.h" #include "ProtocolHandler.h"
#include "ServerConnection.h"
#include "../logger.h" #include "../logger.h"
#include <protocol/buffers.h> #include <protocol/buffers.h>
#include <thread>
using namespace std; using namespace std;

View File

@ -86,6 +86,7 @@ void ProtocolHandler::handleCommandInitIVExpend(ts::Command &cmd) {
log_error(category::connection, tr("Failed to setup crypto ({})"), error); log_error(category::connection, tr("Failed to setup crypto ({})"), error);
return; return;
} }
this->crypt_setupped = true;
if(this->server_type == server_type::UNKNOWN) { if(this->server_type == server_type::UNKNOWN) {
if(cmd[0].has("teaspeak") && cmd["teaspeak"].as<bool>()) { if(cmd[0].has("teaspeak") && cmd["teaspeak"].as<bool>()) {
@ -201,6 +202,7 @@ void ProtocolHandler::handleCommandInitIVExpend2(ts::Command &cmd) {
this->send_command(response, [&](bool success){ this->send_command(response, [&](bool success){
if(success) { if(success) {
/* trigger connected; because the connection has been established on protocol layer */ /* trigger connected; because the connection has been established on protocol layer */
this->crypt_setupped = true;
this->handle->call_connect_result.call(0, true); this->handle->call_connect_result.call(0, true);
this->connection_state = connection_state::CONNECTING; this->connection_state = connection_state::CONNECTING;
} }

View File

@ -6,7 +6,6 @@
#include <iostream> #include <iostream>
#include <tomcrypt.h> #include <tomcrypt.h>
#include <tommath.h> #include <tommath.h>
#include <misc/base64.h>
#include <misc/endianness.h> #include <misc/endianness.h>
#include <protocol/Packet.h> #include <protocol/Packet.h>
#include "audio/VoiceConnection.h" #include "audio/VoiceConnection.h"
@ -22,11 +21,11 @@ using namespace ts;
void ProtocolHandler::handlePacketAck(const std::shared_ptr<ts::protocol::ServerPacket> &ack) { void ProtocolHandler::handlePacketAck(const std::shared_ptr<ts::protocol::ServerPacket> &ack) {
string error; string error;
log_trace(category::connection, tr("Handle packet acknowledge for {}"), be2le16(&ack->data()[0])); log_trace(category::connection, tr("Handle packet acknowledge for {}"), be2le16(&ack->data()[0]));
if(!this->acknowledge_handler.process_acknowledge(*ack, error)) { } this->acknowledge_handler.process_acknowledge(ack->type().type(), ack->data(), error);
} }
void ProtocolHandler::handlePacketCommand(const std::shared_ptr<ts::protocol::ServerPacket> &packet) { void ProtocolHandler::handlePacketCommand(const std::shared_ptr<ts::protocol::ServerPacket> &packet) {
//cout << "Received command: " << packet->data().string() << endl; cout << "Received command: " << packet->data().string() << endl;
std::unique_ptr<Command> command; std::unique_ptr<Command> command;
try { try {

View File

@ -141,7 +141,7 @@ connection.callback_disconnect = reason => {
const do_connect = () => { const do_connect = () => {
connection.connect({ connection.connect({
timeout: 5000, timeout: 5000,
remote_port: 9988, remote_port: 9987,
//remote_host: "188.40.240.20", /* twerion */ //remote_host: "188.40.240.20", /* twerion */
remote_host: "localhost", remote_host: "localhost",
//remote_host: "ts.teaspeak.de", //remote_host: "ts.teaspeak.de",