Fixed the invalid packet splitting algorithm

This commit is contained in:
WolverinDEV 2020-04-25 11:26:00 +02:00
parent 40dfbd64fa
commit ac89b3a423

View File

@ -499,6 +499,7 @@ void VoiceClientConnection::execute_resend(const std::chrono::system_clock::time
this->resend_queue_tail = &packet->next; this->resend_queue_tail = &packet->next;
send_count++; send_count++;
buffer->resend_count++;
this->packet_statistics().send_command((protocol::PacketType) buffer->packet_type, buffer->packet_full_id); this->packet_statistics().send_command((protocol::PacketType) buffer->packet_type, buffer->packet_full_id);
} }
} }
@ -657,7 +658,8 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
uint8_t head_pflags{0}; uint8_t head_pflags{0};
PacketType ptype{low ? PacketType::COMMAND_LOW : PacketType::COMMAND}; PacketType ptype{low ? PacketType::COMMAND_LOW : PacketType::COMMAND};
protocol::OutgoingServerPacket *packets_head{nullptr}; protocol::OutgoingServerPacket *packets_head{nullptr};
protocol::OutgoingServerPacket *packets_tail{nullptr}; protocol::OutgoingServerPacket **packets_tail{&packets_head};
/* only compress "long" commands */ /* only compress "long" commands */
if(command.size() > 100) { if(command.size() > 100) {
size_t max_compressed_payload_size = compression::qlz_compressed_size(command.data(), command.length()); size_t max_compressed_payload_size = compression::qlz_compressed_size(command.data(), command.length());
@ -671,7 +673,7 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
} }
/* we don't need to make the command longer than it is */ /* we don't need to make the command longer than it is */
if(compressed_size < command.length()) { if(compressed_size < command.length() || this->client->getType() == ClientType::CLIENT_TEAMSPEAK) { /* TS3 requires each splituped packet to be compressed */
own_data_buffer = true; own_data_buffer = true;
data_buffer = (char*) compressed_buffer; data_buffer = (char*) compressed_buffer;
own_data_buffer_ptr = compressed_buffer; own_data_buffer_ptr = compressed_buffer;
@ -686,23 +688,24 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
if(data_length > MAX_COMMAND_PACKET_PAYLOAD_LENGTH) { if(data_length > MAX_COMMAND_PACKET_PAYLOAD_LENGTH) {
auto chunk_count = (size_t) ceil((float) data_length / (float) MAX_COMMAND_PACKET_PAYLOAD_LENGTH); auto chunk_count = (size_t) ceil((float) data_length / (float) MAX_COMMAND_PACKET_PAYLOAD_LENGTH);
auto chunk_size = (size_t) ceil((float) data_length / (float) chunk_count); auto chunk_size = (size_t) ceil((float) data_length / (float) chunk_count);
auto packet = protocol::allocate_outgoing_packet(chunk_size);
packets_head = packet;
while(true) {
packet->type_and_flags = ptype_and_flags;
while(true) {
auto bytes = min(chunk_size, data_length); auto bytes = min(chunk_size, data_length);
auto packet = protocol::allocate_outgoing_packet(bytes);
packet->type_and_flags = ptype_and_flags;
memcpy(packet->payload, data_buffer, bytes); memcpy(packet->payload, data_buffer, bytes);
data_length -= bytes; *packets_tail = packet;
if(data_length == 0) packets_tail = &packet->next;
break;
data_buffer += bytes;
packet->next = protocol::allocate_outgoing_packet(bytes); data_length -= bytes;
packet = packet->next; if(data_length == 0) {
packet->type_and_flags |= PacketFlag::Fragmented;
break;
}
data_buffer += bytes;
} }
packets_tail = packet; packets_head->type_and_flags |= PacketFlag::Fragmented;
} else { } else {
auto packet = protocol::allocate_outgoing_packet(data_length); auto packet = protocol::allocate_outgoing_packet(data_length);
packet->type_and_flags = ptype_and_flags; packet->type_and_flags = ptype_and_flags;
@ -710,7 +713,7 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
memcpy(packet->payload, data_buffer, data_length); memcpy(packet->payload, data_buffer, data_length);
packets_head = packet; packets_head = packet;
packets_tail = packet; packets_tail = &packet->next;
} }
@ -726,11 +729,7 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
head = head->next; head = head->next;
} }
} }
/* if head = tail, fragmented will not be enabled (2x xored) */
packets_head->type_and_flags |= head_pflags; packets_head->type_and_flags |= head_pflags;
packets_head->type_and_flags ^= PacketFlag::Fragmented;
packets_tail->type_and_flags ^= PacketFlag::Fragmented;
/* do this before the next ptr might get modified due to the write queue */ /* do this before the next ptr might get modified due to the write queue */
auto statistics = this->client ? this->client->connectionStatistics : nullptr; auto statistics = this->client ? this->client->connectionStatistics : nullptr;
@ -754,7 +753,7 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
head->ref(); head->ref();
/* Even thou the packet is yet unencrypted, it will be encrypted with the next write. The next write will be before the next resend because the next ptr must be null in order to resend a packet */ /* Even thou the packet is yet unencrypted, it will be encrypted with the next write. The next write will be before the next resend because the next ptr must be null in order to resend a packet */
if(head == packets_tail) if(&head->next == packets_tail)
this->acknowledge_handler.process_packet(ptype, full_packet_id, head, std::move(ack_listener)); this->acknowledge_handler.process_packet(ptype, full_packet_id, head, std::move(ack_listener));
else else
this->acknowledge_handler.process_packet(ptype, full_packet_id, head, nullptr); this->acknowledge_handler.process_packet(ptype, full_packet_id, head, nullptr);
@ -766,7 +765,7 @@ void VoiceClientConnection::send_command(const std::string_view &command, bool l
{ {
std::lock_guard qlock{this->write_queue_mutex}; std::lock_guard qlock{this->write_queue_mutex};
*this->write_queue_tail = packets_head; *this->write_queue_tail = packets_head;
this->write_queue_tail = &packets_tail->next; this->write_queue_tail = packets_tail;
} }
this->triggerWrite(); this->triggerWrite();