A lot of updates

This commit is contained in:
WolverinDEV
2020-01-27 02:21:39 +01:00
parent 1de3eee117
commit aaea9b9339
33 changed files with 387 additions and 447 deletions
+222 -257
View File
@@ -13,8 +13,8 @@
//#define LOG_AUTO_ACK_AUTORESPONSE
//#define FUZZING_TESTING_INCOMMING
//#define FUZZING_TESTING_OUTGOING
#define FIZZING_TESTING_DISABLE_HANDSHAKE
#define FUZZING_TESTING_DROP 5
//#define FIZZING_TESTING_DISABLE_HANDSHAKE
#define FUZZING_TESTING_DROP 8
#define FUZZING_TESTING_DROP_MAX 10
//#define CONNECTION_NO_STATISTICS
@@ -65,7 +65,7 @@ void VoiceClientConnection::triggerWrite() {
//Message handle methods
void VoiceClientConnection::handleDatagramReceived(const pipes::buffer_view& buffer) {
void VoiceClientConnection::handle_incoming_datagram(const pipes::buffer_view& buffer) {
#ifdef FUZZING_TESTING_INCOMMING
#ifdef FIZZING_TESTING_DISABLE_HANDSHAKE
if (this->client->state == ConnectionState::CONNECTED) {
@@ -79,226 +79,171 @@ void VoiceClientConnection::handleDatagramReceived(const pipes::buffer_view& buf
#endif
#endif
auto packet = ClientPacket::from_buffer(buffer);
auto packet_type = packet->type();
auto packet_id = packet->packetId();
auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW;
if(packet_type.type() < 0 || packet_type.type() >= this->_packet_buffers.size()) {
logError(this->client->getServerId(), "{} Received invalid packet. Invalid packet type {}. Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client), packet_type.type());
IncomingClientPacketParser packet_parser{buffer};
if(!packet_parser.valid()) {
logTrace(this->client->getServerId(), "{} Received invalid packet. Dropping.", CLIENT_STR_LOG_PREFIX_(this->client));
return;
}
assert(packet_parser.type() >= 0 && packet_parser.type() < this->incoming_generation_estimators.size());
packet_parser.set_estimated_generation(this->incoming_generation_estimators[packet_parser.type()].visit_packet(packet_parser.packet_id()));
auto& read_queue = this->_packet_buffers[packet_type.type()];
packet->generationId(read_queue.generation(packet_id));
auto is_command = packet_parser.type() == protocol::COMMAND || packet_parser.type() == protocol::COMMAND_LOW;
/* pretest if the packet is worth the effort of decoding it */
if(is_command) {
/* handle the order stuff */
auto& fragment_buffer = this->_command_fragment_buffers[command_fragment_buffer_index(packet_parser.type())];
if(ordered) {
unique_lock queue_lock(read_queue.buffer_lock);
auto result = read_queue.accept_index(packet_id);
unique_lock queue_lock(fragment_buffer.buffer_lock);
auto result = fragment_buffer.accept_index(packet_parser.packet_id());
if(result != 0) { /* packet index is ahead buffer index */
debugMessage(this->client->getServerId(), "{} Got packet of type {} which is out of the buffer range of {} ({}). Packet ID: {}, Current index: {}. Dropping packet",
CLIENT_STR_LOG_PREFIX_(this->client),
packet_type.name(),
read_queue.capacity(),
debugMessage(this->client->getServerId(), "{} Dropping command packet because command assembly buffer has an {} ({}|{})",
CLIENT_STR_LOG_PREFIX_(this->client),
result == -1 ? "underflow" : "overflow",
packet_id,
read_queue.current_index()
fragment_buffer.capacity(),
fragment_buffer.current_index()
);
if(result == -1) { /* underflow */
/* we've already got the packet, but the client dosnt know that so we've to send the acknowledge again */
if(this->client->crypto.protocol_encrypted && (packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow)){ //needs an acknowledge
this->client->sendAcknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow);
}
/* we've already got the packet, but the client dosn't know that so we've to send the acknowledge again */
if(this->client->crypto.protocol_encrypted)
this->client->sendAcknowledge(packet_parser.packet_id(), packet_parser.type() == protocol::COMMAND_LOW);
}
return;
}
}
packet->setEncrypted(!packet->has_flag(PacketFlag::Unencrypted)); // && packet->type() != PacketType::Init1
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){
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";
if(this->client->state == ConnectionState::INIT_LOW && packet->type() != PacketTypeInfo::Init1){
//Sends command packet as legacy support (skip step 1-3 | Direct clientinit with default key)
if(this->client->state == ConnectionState::INIT_LOW && packet_parser.type() != protocol::INIT1)
return;
}
if(!this->crypt_handler.progressPacketIn(packet.get(), error, false)){
//FIXME Only try to decrypt by default when its no flood attack!
if(!this->client->crypto.client_init && !this->crypt_handler.use_default()) {
if(!this->crypt_handler.progressPacketIn(packet.get(), error, true)){
debugMessage(
this->client->getServerId(),
"{} Cant decrypt packet even with default key! Type: {}, Error: {}, Packet ID: {}, Generation: {}",
CLIENT_STR_LOG_PREFIX_(this->client),
packet->type().name(),
error,
packet_id,
packet->generationId()
);
return;
} else {
debugMessage(
this->client->getServerId(),
"{} Cant decrypt packet with configured key {}. Error: {}. Succeeded with default key!",
CLIENT_STR_LOG_PREFIX_(this->client),
packet->type().name(),
error
);
}
/* decrypt the packet if needed */
if(packet_parser.is_encrypted()) {
std::string error;
CryptHandler::key_t crypt_key{};
CryptHandler::nonce_t crypt_nonce{};
auto data = (uint8_t*) packet_parser.mutable_data_ptr();
bool use_default_key{!this->client->crypto.protocol_encrypted}, decrypt_result;
decrypt_packet:
if(use_default_key) {
crypt_key = CryptHandler::default_key;
crypt_nonce = CryptHandler::default_nonce;
} else {
bool succeeded = false;
if(packet_type == PacketTypeInfo::Voice) {
/* FIXME: This try and error should not happen! */
packet->generationId(packet->generationId() + 1);
succeeded = this->crypt_handler.progressPacketIn(packet.get(), error, false);
}
if(succeeded) {
auto old_packet_id = read_queue.current_index();
read_queue.set_generation_packet(packet->generationId(), packet->packetId());
logWarning(this->client->getServerId(), "{} Voice packet generation counter missed generation increasement. From {} to {} from packet id {} to {}",
CLIENT_STR_LOG_PREFIX_(this->client),
packet->generationId() - 1,
packet->generationId(),
old_packet_id,
packet->packetId()
);
} else {
debugMessage(
this->client->getServerId(),
"{} Cant decrypt packet of type {}. Packet ID: {}, Estimated generation: {}, Full counter: {}. Dropping packet. Error: {}",
CLIENT_STR_LOG_PREFIX_(this->client),
packet->type().name(),
packet->packetId(),
packet->generationId(),
read_queue.full_index(),
error
);
if(!this->crypt_handler.generate_key_nonce(true, packet_parser.type(), packet_parser.packet_id(), packet_parser.estimated_generation(), crypt_key, crypt_nonce)) {
logError(this->client->getServerId(), "{} Failed to generate crypt key/nonce. This should never happen! Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client));
return;
}
}
}
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){
if(packet->has_flag(PacketFlag::Unencrypted) && this->client->state != ConnectionState::INIT_HIGH){
this->client->disconnect("Invalid packet. Command should not be unencrypted!");
logger::logger(this->client->getServer()->getServerId())->error("{} Voice manager {}/{} tried to send a unencrypted command packet.", CLIENT_STR_LOG_PREFIX_(this->client), client->getDisplayName(), this->client->getLoggingPeerIp());
return;
decrypt_result = this->crypt_handler.decrypt(
data + IncomingClientPacketParser::kHeaderOffset, IncomingClientPacketParser::kHeaderLength,
data + IncomingClientPacketParser::kPayloadOffset, packet_parser.payload_length(),
data,
crypt_key, crypt_nonce,
error
);
if(!decrypt_result) {
if(!this->client->crypto.client_init) {
if(use_default_key) {
logTrace(this->client->getServerId(), "{} Failed to decrypt packet with default key ({}). Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client), error);
return;
} else {
logTrace(this->client->getServerId(), "{} Failed to decrypt packet ({}). Trying with default key.", CLIENT_STR_LOG_PREFIX_(this->client), error);
use_default_key = true;
goto decrypt_packet;
}
} else {
logTrace(this->client->getServerId(), "{} Failed to decrypt packet ({}). Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client), error);
return;
}
}
packet_parser.set_decrypted();
} else if(is_command && this->client->state != ConnectionState::INIT_HIGH) {
logTrace(this->client->getServerId(), "{} Voice client {}/{} tried to send a unencrypted command packet. Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client), client->getDisplayName(), this->client->getLoggingPeerIp());
return;
}
#ifndef CONNECTION_NO_STATISTICS
if(this->client && this->client->getServer())
this->client->connectionStatistics->logIncomingPacket(*packet);
this->client->connectionStatistics->logIncomingPacket(stats::ConnectionStatistics::category::from_type(packet_parser.type()), buffer.length());
#endif
#ifdef LOG_INCOMPING_PACKET_FRAGMENTS
debugMessage(lstream << CLIENT_LOG_PREFIX << "Recived packet. PacketId: " << packet->packetId() << " PacketType: " << packet->type().name() << " Flags: " << packet->flags() << " - " << packet->data() << endl);
#endif
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ //needs an acknowledge
if(this->client->crypto.protocol_encrypted) {
#ifdef LOG_AUTO_ACK_AUTORESPONSE
logMessage(this->client->getServerId(), "{}[Ack] Sending ack for incoming command packet {}", CLIENT_STR_LOG_PREFIX_(this->client), packet->packetId());
#endif
this->client->sendAcknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow);
} else {
debugMessage(this->client->getServerId(), "{}[Ack] Ignoring ack for {}", CLIENT_STR_LOG_PREFIX_(this->client), packet->packetId());
}
}
if(is_command) {
auto& fragment_buffer = this->_command_fragment_buffers[command_fragment_buffer_index(packet_parser.type())];
CommandFragment fragment_entry{
packet_parser.packet_id(),
packet_parser.estimated_generation(),
{
unique_lock queue_lock(read_queue.buffer_lock);
packet_parser.flags(),
(uint32_t) packet_parser.payload_length(),
packet_parser.payload().own_buffer()
};
if(ordered) { /* ordered */
if(!read_queue.insert_index(packet_id, move(packet))) {
debugMessage(this->client->getServerId(), "{} Got ordered packet of type {} which is out of the buffer range of {}. Packet ID: {}, Full index: {}. Dropping packet",
CLIENT_STR_LOG_PREFIX_(this->client),
packet_type.name(),
read_queue.capacity(),
packet_id,
read_queue.full_index()
);
/* return; dont stop here because we've to progress the packets */
}
} else {
//TODO: Needs rethinking because read_queue.push_back increases the index, but this has not to be the packet id
if(!read_queue.push_back(move(packet))) {
debugMessage(this->client->getServerId(), "{} Got unordered packet of type {} which is out of the buffer capacity of {}. Packet ID: {}. Dropping packet.",
CLIENT_STR_LOG_PREFIX_(this->client),
packet_type.name(),
read_queue.capacity(),
packet_id,
read_queue.full_index()
);
}
{
//A max entropy of 16 packets should not happen. This indicates more that 16 or more packets got lost
auto current_index = read_queue.current_index();
if(current_index + 16 < packet_id)
read_queue.set_full_index_to(packet_id);
{
unique_lock queue_lock(fragment_buffer.buffer_lock);
if(!fragment_buffer.insert_index(packet_parser.packet_id(), std::move(fragment_entry))) {
logTrace(this->client->getServerId(), "{} Failed to insert command packet into command packet buffer.", CLIENT_STR_LOG_PREFIX_(this->client));
return;
}
}
this->client->sendAcknowledge(packet_parser.packet_id(), packet_parser.type() == protocol::COMMAND_LOW);
auto voice_server = this->client->voice_server;
if(voice_server)
voice_server->schedule_command_handling(this->client);
} else {
if(packet_parser.type() == protocol::VOICE || packet_parser.type() == protocol::VOICE_WHISPER)
this->client->handlePacketVoice(packet_parser);
else if(packet_parser.type() == protocol::ACK || packet_parser.type() == protocol::ACK_LOW)
this->client->handlePacketAck(packet_parser);
else if(packet_parser.type() == protocol::PING || packet_parser.type() == protocol::PONG)
this->client->handlePacketPing(packet_parser);
else {
logError(this->client->getServerId(), "{} Received hand decoded packet, but we've no method to handle it. Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client));
}
}
auto voice_server = this->client->voice_server;
if(voice_server)
voice_server->schedule_execute(this->client);
}
bool VoiceClientConnection::verify_encryption(const pipes::buffer_view &packet /* incl. mac etc */) {
if((packet[12] & 0x80) != 0) /* we want an encrypted packet to verify the encryption */
return false;
bool VoiceClientConnection::verify_encryption(const pipes::buffer_view &buffer /* incl. mac etc */) {
IncomingClientPacketParser packet_parser{buffer};
if(!packet_parser.valid() || !packet_parser.is_encrypted()) return false;
auto packet_type = (protocol::PacketType) (packet[12] & 0xF);
if(packet_type == protocol::PING || packet_type == protocol::PONG) return false; /* these packets could never be encrypted */
auto packet_id = (uint16_t) be2le16(&packet[8]);
auto generation = this->_packet_buffers[packet_type].generation(packet_id);
return this->crypt_handler.verify_encryption(packet, packet_id, generation);
assert(packet_parser.type() >= 0 && packet_parser.type() < this->incoming_generation_estimators.size());
return this->crypt_handler.verify_encryption(buffer, packet_parser.packet_id(), this->incoming_generation_estimators[packet_parser.type()].generation());
}
void VoiceClientConnection::execute_handle_packet(const std::chrono::system_clock::time_point& /* scheduled */) {
void VoiceClientConnection::execute_handle_command_packets(const std::chrono::system_clock::time_point& /* scheduled */) {
if(this->client->state == ConnectionState::DISCONNECTED || !this->client->getServer())
return;
bool reexecute_handle = false;
//TODO: Remove the buffer_execute_lock and use the one within the this->client->handlePacketCommand method
unique_lock<std::recursive_timed_mutex> buffer_execute_lock;
auto packet = this->next_reassembled_packet(buffer_execute_lock, reexecute_handle);
pipes::buffer payload{};
auto reexecute_handle = this->next_reassembled_command(buffer_execute_lock, payload);
if(packet){
if(!payload.empty()){
auto startTime = system_clock::now();
try {
const auto packet_type = packet->type();
if(packet_type == PacketTypeInfo::Command || packet_type == PacketTypeInfo::CommandLow)
this->client->handlePacketCommand(packet);
else if(packet_type == PacketTypeInfo::Ack || packet_type == PacketTypeInfo::AckLow)
this->client->handlePacketAck(packet);
else if(packet_type == PacketTypeInfo::Voice || packet_type == PacketTypeInfo::VoiceWhisper)
this->client->handlePacketVoice(packet);
else if(packet_type == PacketTypeInfo::Ping || packet_type == PacketTypeInfo::Pong)
this->client->handlePacketPing(packet);
else if(packet_type == PacketTypeInfo::Init1)
this->client->handlePacketInit(packet);
this->client->handlePacketCommand(payload);
} catch (std::exception& ex) {
logCritical(this->client->getServerId(), "{} Exception reached root tree! {}", CLIENT_STR_LOG_PREFIX_(this->client), ex.what());
}
auto end = system_clock::now();
if(end - startTime > milliseconds(10)) {
if(packet->type() != PacketTypeInfo::Command && packet->type() != PacketTypeInfo::CommandLow) {
logError(this->client->getServerId(),
"{} Handling of packet {} needs more than 10ms ({}ms)",
CLIENT_STR_LOG_PREFIX_(this->client),
packet->type().name(),
duration_cast<milliseconds>(end - startTime).count()
);
}
logError(this->client->getServerId(),
"{} Handling of command packet needs more than 10ms ({}ms)",
CLIENT_STR_LOG_PREFIX_(this->client),
duration_cast<milliseconds>(end - startTime).count()
);
}
}
if(buffer_execute_lock.owns_lock())
@@ -306,24 +251,20 @@ void VoiceClientConnection::execute_handle_packet(const std::chrono::system_cloc
auto voice_server = this->client->voice_server;
if(voice_server && reexecute_handle)
this->client->voice_server->schedule_execute(this->client);
this->client->voice_server->schedule_command_handling(this->client);
}
/* buffer_execute_lock: lock for in order execution */
unique_ptr<protocol::ClientPacket> VoiceClientConnection::next_reassembled_packet(unique_lock<std::recursive_timed_mutex>& buffer_execute_lock, bool& more) {
packet_buffer_t* buffer = nullptr;
bool VoiceClientConnection::next_reassembled_command(unique_lock<std::recursive_timed_mutex>& buffer_execute_lock, pipes::buffer& result) {
command_fragment_buffer_t* buffer{nullptr};
unique_lock<std::recursive_timed_mutex> buffer_lock; /* general buffer lock */
bool have_more{false};
{
auto base_index = this->_packet_buffers_index;
auto select_index = base_index;
auto max_index = this->_packet_buffers.size();
//FIXME: Currently command low packets cant be handeled if there is a command packet stuck in reassamble
for(uint8_t index = 0; index < max_index; index++) {
if(!buffer)
select_index++;
auto& buf = this->_packet_buffers[base_index++ % max_index];
/* handle commands before command low packets */
for(auto& buf : this->_command_fragment_buffers) {
unique_lock ring_lock(buf.buffer_lock, try_to_lock);
if(!ring_lock.owns_lock()) continue;
@@ -335,119 +276,94 @@ unique_ptr<protocol::ClientPacket> VoiceClientConnection::next_reassembled_packe
buffer_lock = move(ring_lock);
buffer = &buf;
} else {
more = true;
have_more = true;
break;
}
}
}
this->_packet_buffers_index = static_cast<uint8_t>(select_index % max_index); /* guarantee that we will not hangup with commands! */
}
if(!buffer)
return nullptr; /* we've no packets */
return false; /* we've no packets */
auto current_packet = &*buffer->slot_value(0);
if(!current_packet) {
logCritical(this->client->getServer()->getServerId(), "buffer->slot_value(0) returned nullptr, but set flag has been set!");
return buffer->pop_front(); /* should be null! */
}
uint8_t packet_flags{0};
pipes::buffer payload{};
if(current_packet->type() != PacketTypeInfo::Command && current_packet->type() != PacketTypeInfo::CommandLow) {
auto tmp = buffer->pop_front(); /* we don't have to reassemble anything */
more |= buffer->front_set(); /* set the more flag if we know that we have more of this packet */
return tmp;
}
unique_ptr<ClientPacket> final_packet;
uint16_t sequence_length = 1;
if(current_packet->has_flag(PacketFlag::Fragmented)) {
size_t buffer_length = ClientPacket::META_SIZE;
/* lets find out if we've to reassemble the packet */
if(buffer->slot_value(0).packet_flags & PacketFlag::Fragmented) {
uint16_t sequence_length = 1;
size_t total_payload_length{0};
do {
if(sequence_length >= buffer->capacity()) {
logError(this->client->getServerId(), "{} Received fragmented packets which have a too long order. Dropping queue, which will cause a client drop.", CLIENT_STR_LOG_PREFIX_(this->client));
logError(this->client->getServerId(), "{} Command fragment buffer is full, and there is not fragmented packet end. Dropping full buffer which will probably cause a connection loss.", CLIENT_STR_LOG_PREFIX_(this->client));
buffer->clear();
return nullptr; /* we've nothing to handle */
return false; /* we've nothing to handle */
}
buffer_length += current_packet->data_length();
current_packet = &*buffer->slot_value(sequence_length++);
} while(current_packet && !current_packet->has_flag(PacketFlag::Fragmented));
if(!current_packet)
return nullptr; /* we haven't found the end yet! */
buffer_length += current_packet->data_length();
if(!buffer->slot_set(sequence_length))
return false; /* we need more packets */
/* okey we have all fragments lets reassemble */
auto& packet = buffer->slot_value(sequence_length++);
total_payload_length += packet.payload_length;
if(packet.packet_flags & PacketFlag::Fragmented) {
/* yep we find the end */
break;
}
} while(true);
/* ok we have all fragments lets reassemble */
/*
* Packet sequence could never be so long. If it is so then the data_length() returned an invalid value.
* We're checking it here because we dont want to make a huge allocation
*/
assert(buffer_length < 512 * 1024 * 1024);
assert(total_payload_length < 512 * 1024 * 1024);
pipes::buffer packet_buffer{buffer_length};
pipes::buffer packet_buffer{total_payload_length};
char* packet_buffer_ptr = &packet_buffer[0];
size_t packet_count = 0;
unique_ptr<ClientPacket> packet;
/* initialize packet flags etc */
{
packet = buffer->pop_front();
packet_count++;
if(!packet) {
logCritical(this->client->getServer()->getServerId(), "buffer->pop_front() returned nullptr, but set flag has been set (0)!");
return nullptr;
}
const auto length = packet->buffer().length();
memcpy(packet_buffer_ptr, &packet->buffer()[0], length);
packet_buffer_ptr += length;
}
packet_flags = buffer->slot_value(0).packet_flags;
while(packet_count < sequence_length) {
packet = buffer->pop_front();
auto fragment = buffer->pop_front();
memcpy(packet_buffer_ptr, fragment.payload.data_ptr(), fragment.payload_length);
packet_buffer_ptr += fragment.payload_length;
packet_count++;
if(!packet) {
logCritical(this->client->getServer()->getServerId(), "buffer->pop_front() returned nullptr, but set flag has been set (1)!");
return nullptr;
}
const auto length = packet->data_length();
memcpy(packet_buffer_ptr, &packet->data()[0], length);
packet_buffer_ptr += length;
}
#ifndef _NDEBUG
if((packet_buffer_ptr - 1) != &packet_buffer[packet_buffer.length() - 1]) {
logCritical(this->client->getServer()->getServerId(),
"Buffer over/underflow: packet_buffer_ptr != &packet_buffer[packet_buffer.length() - 1]; packet_buffer_ptr := {}; packet_buffer.end() := {}",
(void*) packet_buffer_ptr,
(void*) &packet_buffer[packet_buffer.length() - 1]
"Buffer over/underflow: packet_buffer_ptr != &packet_buffer[packet_buffer.length() - 1]; packet_buffer_ptr := {}; packet_buffer.end() := {}",
(void*) packet_buffer_ptr,
(void*) &packet_buffer[packet_buffer.length() - 1]
);
}
final_packet = ClientPacket::from_buffer(packet_buffer);
final_packet->setCompressed(final_packet->has_flag(PacketFlag::Compressed));
#endif
} else {
final_packet = buffer->pop_front();
if(!final_packet) {
logCritical(this->client->getServer()->getServerId(), "buffer->pop_front() returned nullptr, but set flag has been set (3)!");
return nullptr;
}
auto packet = buffer->pop_front();
packet_flags = packet.packet_flags;
payload = packet.payload;
}
more |= buffer->front_set(); /* set the more flag if we have more to process */
have_more |= buffer->front_set(); /* set the more flag if we have more to process */
buffer_lock.unlock();
std::string error = "success";
if(!this->compress_handler.progressPacketIn(&*final_packet, error)) {
logError(this->client->getServerId(), "{} Failed to decompress received packet. Error: {}", CLIENT_STR_LOG_PREFIX_(this->client), error);
final_packet = nullptr;
if(packet_flags & PacketFlag::Compressed) {
std::string error{};
auto decompressed_size = compression::qlz_decompressed_size(payload.data_ptr(), payload.length());
auto buffer = buffer::allocate_buffer(decompressed_size);
if(!compression::qlz_decompress_payload(payload.data_ptr(), buffer.data_ptr(), &decompressed_size)) {
logTrace(this->client->getServerId(), "{} Failed to decompress received command. Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client));
return false;
}
payload = buffer.range(0, decompressed_size);
}
return final_packet;
result = std::move(payload);
return have_more;
}
@@ -499,7 +415,7 @@ bool VoiceClientConnection::prepare_packet_for_write(vector<pipes::buffer> &resu
string error = "success";
if(packet->type().compressable() && !packet->memory_state.fragment_entry) {
if(packet->type().compressable() && !packet->memory_state.fragment_entry && false) {
packet->enable_flag(PacketFlag::Compressed);
if(!this->compress_handler.progressPacketOut(packet.get(), error)) {
logError(this->getClient()->getServerId(), "{} Could not compress outgoing packet.\nThis could cause fatal failed for the client.\nError: {}", error);
@@ -560,12 +476,33 @@ bool VoiceClientConnection::prepare_packet_for_write(vector<pipes::buffer> &resu
work_lock.unlock(); /* the rest could be unordered */
CryptHandler::key_t crypt_key{};
CryptHandler::nonce_t crypt_nonce{};
auto statistics = this->client ? this->client->connectionStatistics : nullptr;
for(const auto& fragment : fragments) {
if(!this->crypt_handler.progressPacketOut(fragment.get(), error, false)){
logError(this->client->getServerId(), "{} Failed to encrypt packet. Error: {}", CLIENT_STR_LOG_PREFIX_(this->client), error);
return false;
if(fragment->has_flag(PacketFlag::Unencrypted)) {
this->crypt_handler.write_default_mac(fragment->mac().data_ptr());
} else {
if(!this->client->crypto.protocol_encrypted) {
crypt_key = CryptHandler::default_key;
crypt_nonce = CryptHandler::default_nonce;
} else {
if(!this->crypt_handler.generate_key_nonce(false, fragment->type().type(), fragment->packetId(), fragment->generationId(), crypt_key, crypt_nonce)) {
logError(this->client->getServerId(), "{} Failed to generate crypt key/nonce for sending a packet. This should never happen! Dropping packet.", CLIENT_STR_LOG_PREFIX_(this->client));
return false;
}
}
auto crypt_result = this->crypt_handler.encrypt(fragment->header().data_ptr(), fragment->header().length(),
fragment->data().data_ptr(), fragment->data().length(),
fragment->mac().data_ptr(),
crypt_key, crypt_nonce, error);
if(!crypt_result){
logError(this->client->getServerId(), "{} Failed to encrypt packet. Error: {}", CLIENT_STR_LOG_PREFIX_(this->client), error);
return false;
}
}
#ifndef CONNECTION_NO_STATISTICS
if(statistics)
statistics->logOutgoingPacket(*fragment);
@@ -704,7 +641,35 @@ void VoiceClientConnection::reset() {
{
lock_guard buffer_lock(this->packet_buffer_lock);
for(auto& buffer : this->_packet_buffers)
for(auto& buffer : this->_command_fragment_buffers)
buffer.reset();
}
}
void VoiceClientConnection::force_insert_command(const pipes::buffer_view &buffer) {
CommandFragment fragment_entry{
0,
0,
PacketFlag::Unencrypted,
(uint32_t) buffer.length(),
buffer.own_buffer()
};
{
auto& fragment_buffer = this->_command_fragment_buffers[command_fragment_buffer_index(protocol::COMMAND)];
unique_lock queue_lock(fragment_buffer.buffer_lock);
fragment_buffer.push_front(std::move(fragment_entry));
}
auto voice_server = this->client->voice_server;
if(voice_server)
voice_server->schedule_command_handling(this->client);
}
void VoiceClientConnection::register_initiv_packet() {
auto& fragment_buffer = this->_command_fragment_buffers[command_fragment_buffer_index(protocol::COMMAND)];
unique_lock buffer_lock(fragment_buffer.buffer_lock);
fragment_buffer.set_full_index_to(1); /* the first packet (0) is already the clientinitiv packet */
}