Improved abort signal printing and some reformats

This commit is contained in:
WolverinDEV 2021-01-14 22:16:56 +01:00
parent f2c5b5d750
commit 94c7eb2f39
14 changed files with 143 additions and 95 deletions

View File

@ -116,8 +116,9 @@ bool FileClient::enqueue_disk_buffer_bytes(const void *snd_buffer, size_t size)
size_t buffer_size; size_t buffer_size;
{ {
std::lock_guard block{this->disk_buffer.mutex}; std::lock_guard block{this->disk_buffer.mutex};
if(this->disk_buffer.write_disconnected) if(this->disk_buffer.write_disconnected) {
goto write_disconnected; goto write_disconnected;
}
*this->disk_buffer.buffer_tail = tbuffer; *this->disk_buffer.buffer_tail = tbuffer;
this->disk_buffer.buffer_tail = &tbuffer->next; this->disk_buffer.buffer_tail = &tbuffer->next;

View File

@ -133,8 +133,10 @@ bool FileClient::enqueue_network_buffer_bytes(const void *snd_buffer, size_t siz
size_t buffer_size; size_t buffer_size;
{ {
std::lock_guard block{this->network_buffer.mutex}; std::lock_guard block{this->network_buffer.mutex};
if(this->network_buffer.write_disconnected) if(this->network_buffer.write_disconnected) {
goto write_disconnected; goto write_disconnected;
}
*this->network_buffer.buffer_tail = tbuffer; *this->network_buffer.buffer_tail = tbuffer;
this->network_buffer.buffer_tail = &tbuffer->next; this->network_buffer.buffer_tail = &tbuffer->next;
@ -898,8 +900,9 @@ size_t LocalFileTransfer::handle_transfer_read_raw(const std::shared_ptr<FileCli
client->transfer_key.provided_bytes += bytes_write; client->transfer_key.provided_bytes += bytes_write;
} }
if(client->transfer_key.provided_bytes < TRANSFER_KEY_LENGTH) if(client->transfer_key.provided_bytes < TRANSFER_KEY_LENGTH) {
return 0; /* we need more data */ return 0; /* we need more data */
}
if(pipes::SSL::is_ssl((uint8_t*) client->transfer_key.key, client->transfer_key.provided_bytes)) { if(pipes::SSL::is_ssl((uint8_t*) client->transfer_key.key, client->transfer_key.provided_bytes)) {
client->networking.protocol = FileClient::PROTOCOL_HTTPS; client->networking.protocol = FileClient::PROTOCOL_HTTPS;
@ -911,12 +914,14 @@ size_t LocalFileTransfer::handle_transfer_read_raw(const std::shared_ptr<FileCli
memcpy(first_bytes, client->transfer_key.key, TRANSFER_KEY_LENGTH); memcpy(first_bytes, client->transfer_key.key, TRANSFER_KEY_LENGTH);
client->transfer_key.provided_bytes = 0; client->transfer_key.provided_bytes = 0;
if(!this->initialize_client_ssl(client)) if(!this->initialize_client_ssl(client)) {
return (size_t) -1; return (size_t) -1;
}
client->networking.pipe_ssl.process_incoming_data(pipes::buffer_view{first_bytes, TRANSFER_KEY_LENGTH}); client->networking.pipe_ssl.process_incoming_data(pipes::buffer_view{first_bytes, TRANSFER_KEY_LENGTH});
if(length > 0) if(length > 0) {
client->networking.pipe_ssl.process_incoming_data(pipes::buffer_view{buffer, length}); client->networking.pipe_ssl.process_incoming_data(pipes::buffer_view{buffer, length});
}
return client->network_buffer.bytes; return client->network_buffer.bytes;
} else { } else {
client->networking.protocol = FileClient::PROTOCOL_TS_V1; client->networking.protocol = FileClient::PROTOCOL_TS_V1;
@ -1226,8 +1231,9 @@ TransferKeyApplyResult LocalFileTransfer::handle_transfer_key_provided(const std
} }
} }
if(!client->transfer) if(!client->transfer) {
return TransferKeyApplyResult::UNKNOWN_KEY; return TransferKeyApplyResult::UNKNOWN_KEY;
}
if(client->transfer->direction == Transfer::DIRECTION_UPLOAD) { if(client->transfer->direction == Transfer::DIRECTION_UPLOAD) {
auto server = dynamic_pointer_cast<LocalVirtualFileServer>(client->transfer->server); auto server = dynamic_pointer_cast<LocalVirtualFileServer>(client->transfer->server);
@ -1255,14 +1261,16 @@ TransferKeyApplyResult LocalFileTransfer::handle_transfer_key_provided(const std
{ {
std::unique_lock slock{client->state_mutex}; std::unique_lock slock{client->state_mutex};
if(client->state != FileClient::STATE_AWAITING_KEY) if(client->state != FileClient::STATE_AWAITING_KEY) {
return TransferKeyApplyResult::SUCCESS; /* something disconnected the client */ return TransferKeyApplyResult::SUCCESS; /* something disconnected the client */
}
client->state = FileClient::STATE_TRANSFERRING; client->state = FileClient::STATE_TRANSFERRING;
} }
if(auto callback{this->callback_transfer_started}; callback) if(auto callback{this->callback_transfer_started}; callback) {
callback(client->transfer); callback(client->transfer);
}
client->timings.key_received = std::chrono::system_clock::now(); client->timings.key_received = std::chrono::system_clock::now();
return TransferKeyApplyResult::SUCCESS; return TransferKeyApplyResult::SUCCESS;
@ -1283,8 +1291,9 @@ TransferUploadRawResult LocalFileTransfer::handle_transfer_upload_raw(const std:
client->statistics.file_transferred.increase_bytes(write_length); client->statistics.file_transferred.increase_bytes(write_length);
client->enqueue_disk_buffer_bytes(buffer, write_length); client->enqueue_disk_buffer_bytes(buffer, write_length);
this->enqueue_disk_io(client); this->enqueue_disk_io(client);
if(bytesWritten) if(bytesWritten) {
*bytesWritten = write_length; *bytesWritten = write_length;
}
return result; return result;
} }

View File

@ -107,8 +107,9 @@ namespace ts::server::file::networking {
throttle |= this->right->should_throttle(right_timestamp); throttle |= this->right->should_throttle(right_timestamp);
if(!throttle) return false; if(!throttle) return false;
if(right_timestamp.tv_sec > next_timestamp.tv_sec || (right_timestamp.tv_sec == next_timestamp.tv_sec && right_timestamp.tv_usec > next_timestamp.tv_usec)) if(right_timestamp.tv_sec > next_timestamp.tv_sec || (right_timestamp.tv_sec == next_timestamp.tv_sec && right_timestamp.tv_usec > next_timestamp.tv_usec)) {
next_timestamp = right_timestamp; next_timestamp = right_timestamp;
}
return true; return true;
} }
@ -141,8 +142,10 @@ namespace ts::server::file::networking {
std::lock_guard slock{this->mutex}; std::lock_guard slock{this->mutex};
this->total_bytes += bytes; this->total_bytes += bytes;
if(this->span_index != current_span) if(this->span_index != current_span) {
this->history[this->span_index % kAverageTimeCount] = std::exchange(this->span_bytes, 0); this->history[this->span_index % kAverageTimeCount] = std::exchange(this->span_bytes, 0);
}
this->span_index = current_span; this->span_index = current_span;
this->span_bytes += bytes; this->span_bytes += bytes;
} }

2
rtclib

@ -1 +1 @@
Subproject commit 2c08b8759268095b96f3904757300905db1ea61d Subproject commit 449f4f3baab91ba488f83def70193d08f350f193

View File

@ -26,6 +26,18 @@ google_breakpad::ExceptionHandler* globalExceptionHandler = nullptr;
if(signal(s, c) != nullptr) logError(LOG_GENERAL, "Cant setup signal handler for " #s); if(signal(s, c) != nullptr) logError(LOG_GENERAL, "Cant setup signal handler for " #s);
void print_current_exception() {
if(std::current_exception()) {
logCritical(LOG_GENERAL, "Exception reached stack root and cause the server to crash!");
logCritical(LOG_GENERAL, " Type: {}", std::current_exception().__cxa_exception_type()->name());
try {
std::rethrow_exception(std::current_exception());
} catch(std::exception& ex) {
logCritical(LOG_GENERAL, " Message: {}", ex.what());
} catch(...) {}
}
}
extern bool mainThreadDone; extern bool mainThreadDone;
#ifdef BREAKPAD_EXCEPTION_HANDLER #ifdef BREAKPAD_EXCEPTION_HANDLER
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) {
@ -41,15 +53,7 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
} catch (...) { } catch (...) {
logCritical(LOG_GENERAL, "Failed to write/move crash dump!"); logCritical(LOG_GENERAL, "Failed to write/move crash dump!");
} }
if(std::current_exception()) { print_current_exception();
logCritical(LOG_GENERAL, "Exception reached stack root and cause the server to crash!");
logCritical(LOG_GENERAL, " Type: {}", std::current_exception().__cxa_exception_type()->name());
try {
std::rethrow_exception(std::current_exception());
} catch(std::exception& ex) {
logCritical(LOG_GENERAL, " Message: {}", ex.what());
} catch(...) {}
}
logCritical(LOG_GENERAL, "Please report this crash to the TeaSpeak maintainer WolverinDEV"); logCritical(LOG_GENERAL, "Please report this crash to the TeaSpeak maintainer WolverinDEV");
logCritical(LOG_GENERAL, "Official issue and bug tracker url: https://github.com/TeaSpeak/TeaSpeak/issues"); logCritical(LOG_GENERAL, "Official issue and bug tracker url: https://github.com/TeaSpeak/TeaSpeak/issues");
@ -58,7 +62,9 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
terminal::finalize_pipe(); terminal::finalize_pipe();
ts::server::shutdownInstance(ts::config::messages::applicationCrashed); ts::server::shutdownInstance(ts::config::messages::applicationCrashed);
while(!mainThreadDone) threads::self::sleep_for(chrono::seconds(1)); while(!mainThreadDone) {
threads::self::sleep_for(chrono::seconds(1));
}
return succeeded; return succeeded;
} }
#endif #endif
@ -75,6 +81,8 @@ bool ts::syssignal::setup() {
//We cant listen for this signal if stdin ist a atty //We cant listen for this signal if stdin ist a atty
SIG(SIGINT, &ts::syssignal::handleStopSignal); SIG(SIGINT, &ts::syssignal::handleStopSignal);
} }
SIG(SIGABRT, &ts::syssignal::handleAbortSignal);
std::set_terminate(ts::syssignal::handleTerminate);
return true; return true;
} }
@ -116,4 +124,10 @@ void ts::syssignal::handleStopSignal(int signal) {
raise(SIGKILL); raise(SIGKILL);
} }
ts::server::shutdownInstance(); ts::server::shutdownInstance();
}
void ts::syssignal::handleTerminate() {
logCritical(0, "The server crashed (Received a terminate signal)!");
print_current_exception();
} }

View File

@ -8,5 +8,7 @@ namespace ts {
extern bool setup(); extern bool setup();
extern bool setup_threads(); extern bool setup_threads();
extern void handleStopSignal(int); extern void handleStopSignal(int);
extern void handleAbortSignal(int);
extern void handleTerminate();
} }
} }

View File

@ -40,7 +40,6 @@ using namespace ts::token;
constexpr static auto kFileAPITimeout = std::chrono::milliseconds{500}; constexpr static auto kFileAPITimeout = std::chrono::milliseconds{500};
constexpr static auto kMaxClientTransfers = 10; constexpr static auto kMaxClientTransfers = 10;
#define QUERY_PASSWORD_LENGTH 12
//ftgetfilelist cid=1 cpw path=\/ return_code=1:x //ftgetfilelist cid=1 cpw path=\/ return_code=1:x
//Answer: //Answer:
@ -90,8 +89,9 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
} }
} }
if(!query_result->wait_for(kFileAPITimeout)) if(!query_result->wait_for(kFileAPITimeout)) {
return command_result{error::file_api_timeout}; return command_result{error::file_api_timeout};
}
if(!query_result->succeeded()) { if(!query_result->succeeded()) {
debugMessage(this->getServerId(), "{} Failed to query directory: {} / {}", CLIENT_STR_LOG_PREFIX, file::filesystem::directory_query_error_messages[(int) query_result->error().error_type], query_result->error().error_message); debugMessage(this->getServerId(), "{} Failed to query directory: {} / {}", CLIENT_STR_LOG_PREFIX, file::filesystem::directory_query_error_messages[(int) query_result->error().error_type], query_result->error().error_message);
@ -118,8 +118,9 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
} }
const auto& files = query_result->response(); const auto& files = query_result->response();
if(files.empty()) if(files.empty()) {
return command_result{error::database_empty_result}; return command_result{error::database_empty_result};
}
auto return_code = cmd["return_code"].size() > 0 ? cmd["return_code"].string() : ""; auto return_code = cmd["return_code"].size() > 0 ? cmd["return_code"].string() : "";
@ -131,8 +132,9 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
notify_file_list.reset(); notify_file_list.reset();
notify_file_list.put_unchecked(0, "path", cmd["path"].string()); notify_file_list.put_unchecked(0, "path", cmd["path"].string());
notify_file_list.put_unchecked(0, "cid", cmd["cid"].string()); notify_file_list.put_unchecked(0, "cid", cmd["cid"].string());
if(!return_code.empty()) if(!return_code.empty()){
notify_file_list.put_unchecked(0, "return_code", return_code); notify_file_list.put_unchecked(0, "return_code", return_code);
}
} }
auto bulk = notify_file_list.bulk(bulk_index++); auto bulk = notify_file_list.bulk(bulk_index++);

View File

@ -663,8 +663,9 @@ command_result ConnectedClient::handleCommandBanList(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(25); CMD_CHK_AND_INC_FLOOD_POINTS(25);
ServerId sid = this->getServerId(); ServerId sid = this->getServerId();
if (cmd[0].has("sid")) if (cmd[0].has("sid")) {
sid = cmd["sid"]; sid = cmd["sid"];
}
if (sid == 0) { if (sid == 0) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_client_ban_list_global, 1); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_client_ban_list_global, 1);
@ -672,8 +673,9 @@ command_result ConnectedClient::handleCommandBanList(Command &cmd) {
auto server = serverInstance->getVoiceServerManager()->findServerById(sid); auto server = serverInstance->getVoiceServerManager()->findServerById(sid);
if (!server) return command_result{error::parameter_invalid}; if (!server) return command_result{error::parameter_invalid};
if (!permission::v2::permission_granted(1, server->calculate_permission(permission::b_client_ban_list, this->getClientDatabaseId(), this->getType(), 0))) if (!permission::v2::permission_granted(1, server->calculate_permission(permission::b_client_ban_list, this->getClientDatabaseId(), this->getType(), 0))) {
return command_result{permission::b_client_ban_list}; return command_result{permission::b_client_ban_list};
}
} }
//When empty: return command_result{error::database_empty_result}; //When empty: return command_result{error::database_empty_result};

View File

@ -18,8 +18,6 @@ WhisperHandler::~WhisperHandler() {
} }
bool WhisperHandler::validate_whisper_packet(const protocol::ClientPacketParser &packet, bool& match_last_header, void *&payload_ptr, size_t &payload_length) { bool WhisperHandler::validate_whisper_packet(const protocol::ClientPacketParser &packet, bool& match_last_header, void *&payload_ptr, size_t &payload_length) {
std::lock_guard process_lock{this->whisper_head_mutex};
size_t head_length; size_t head_length;
if(packet.flags() & protocol::PacketFlag::NewProtocol) { if(packet.flags() & protocol::PacketFlag::NewProtocol) {
if(packet.payload_length() < 3 + 10) { if(packet.payload_length() < 3 + 10) {
@ -45,19 +43,22 @@ bool WhisperHandler::validate_whisper_packet(const protocol::ClientPacketParser
} }
auto head_ptr = packet.payload().data_ptr<uint8_t>() + 3; auto head_ptr = packet.payload().data_ptr<uint8_t>() + 3;
match_last_header = this->whisper_head_length == head_length && memcmp(this->whisper_head_ptr, head_ptr, head_length) == 0; {
if(!match_last_header) { std::lock_guard process_lock{this->whisper_head_mutex};
if(this->whisper_head_capacity < head_length) { match_last_header = this->whisper_head_length == head_length && memcmp(this->whisper_head_ptr, head_ptr, head_length) == 0;
if(this->whisper_head_ptr) { if(!match_last_header) {
::free(this->whisper_head_ptr); if(this->whisper_head_capacity < head_length) {
if(this->whisper_head_ptr) {
::free(this->whisper_head_ptr);
}
this->whisper_head_ptr = malloc(head_length);
this->whisper_head_capacity = head_length;
} }
this->whisper_head_ptr = malloc(head_length); this->whisper_head_length = head_length;
this->whisper_head_capacity = head_length; memcpy(this->whisper_head_ptr, head_ptr, head_length);
} }
this->whisper_head_length = head_length;
memcpy(this->whisper_head_ptr, head_ptr, head_length);
} }
assert(packet.payload_length() >= head_length + 3); assert(packet.payload_length() >= head_length + 3);

View File

@ -221,10 +221,11 @@ CommandReassembleResult PacketDecoder::try_reassemble_ordered_packet(
ReassembledCommand *&assembled_command) { ReassembledCommand *&assembled_command) {
assert(buffer_lock.owns_lock()); assert(buffer_lock.owns_lock());
if(!buffer.front_set()) if(!buffer.front_set()) {
return CommandReassembleResult::NO_COMMANDS_PENDING; return CommandReassembleResult::NO_COMMANDS_PENDING;
}
uint8_t packet_flags{0}; uint8_t packet_flags;
std::unique_ptr<ReassembledCommand, void(*)(ReassembledCommand*)> rcommand{nullptr, ReassembledCommand::free}; std::unique_ptr<ReassembledCommand, void(*)(ReassembledCommand*)> rcommand{nullptr, ReassembledCommand::free};
@ -234,11 +235,13 @@ CommandReassembleResult PacketDecoder::try_reassemble_ordered_packet(
uint16_t sequence_length{1}; uint16_t sequence_length{1};
size_t total_payload_length{first_buffer.payload_length}; size_t total_payload_length{first_buffer.payload_length};
do { do {
if(sequence_length >= buffer.capacity()) if(sequence_length >= buffer.capacity()) {
return CommandReassembleResult::SEQUENCE_LENGTH_TOO_LONG; return CommandReassembleResult::SEQUENCE_LENGTH_TOO_LONG;
}
if(!buffer.slot_set(sequence_length)) if(!buffer.slot_set(sequence_length)) {
return CommandReassembleResult::NO_COMMANDS_PENDING; /* we need more packets */ return CommandReassembleResult::NO_COMMANDS_PENDING; /* we need more packets */
}
auto& packet = buffer.slot_value(sequence_length++); auto& packet = buffer.slot_value(sequence_length++);
total_payload_length += packet.payload_length; total_payload_length += packet.payload_length;
@ -293,12 +296,14 @@ CommandReassembleResult PacketDecoder::try_reassemble_ordered_packet(
auto compressed_command = std::move(rcommand); auto compressed_command = std::move(rcommand);
auto decompressed_size = compression::qlz_decompressed_size(compressed_command->command(), compressed_command->length()); auto decompressed_size = compression::qlz_decompressed_size(compressed_command->command(), compressed_command->length());
if(decompressed_size > 64 * 1024 * 1024) if(decompressed_size > 64 * 1024 * 1024) {
return CommandReassembleResult::COMMAND_TOO_LARGE; return CommandReassembleResult::COMMAND_TOO_LARGE;
}
rcommand.reset(ReassembledCommand::allocate(decompressed_size)); rcommand.reset(ReassembledCommand::allocate(decompressed_size));
if(!compression::qlz_decompress_payload(compressed_command->command(), rcommand->command(), &decompressed_size)) if(!compression::qlz_decompress_payload(compressed_command->command(), rcommand->command(), &decompressed_size)) {
return CommandReassembleResult::COMMAND_DECOMPRESS_FAILED; return CommandReassembleResult::COMMAND_DECOMPRESS_FAILED;
}
rcommand->set_length(decompressed_size); rcommand->set_length(decompressed_size);
} }

View File

@ -5,7 +5,8 @@
#include <protocol/buffers.h> #include <protocol/buffers.h>
#include <protocol/CompressionHandler.h> #include <protocol/CompressionHandler.h>
#include <protocol/CryptHandler.cpp> #include <protocol/CryptHandler.h>
#include <misc/endianness.h>
using namespace ts; using namespace ts;
using namespace ts::server::server::udp; using namespace ts::server::server::udp;
@ -15,7 +16,7 @@ PacketEncoder::PacketEncoder(ts::connection::CryptHandler *crypt_handler, client
this->acknowledge_manager_.callback_data = this; this->acknowledge_manager_.callback_data = this;
this->acknowledge_manager_.destroy_packet = [](void* packet) { this->acknowledge_manager_.destroy_packet = [](void* packet) {
reinterpret_cast<OutgoingServerPacket*>(packet)->unref(); reinterpret_cast<protocol::OutgoingServerPacket*>(packet)->unref();
}; };
this->acknowledge_manager_.callback_resend_failed = [](void* this_ptr, const auto& entry) { this->acknowledge_manager_.callback_resend_failed = [](void* this_ptr, const auto& entry) {
auto encoder = reinterpret_cast<PacketEncoder*>(this_ptr); auto encoder = reinterpret_cast<PacketEncoder*>(this_ptr);
@ -37,7 +38,7 @@ void PacketEncoder::reset() {
rhead = std::exchange(this->resend_queue_head, nullptr); rhead = std::exchange(this->resend_queue_head, nullptr);
this->encrypt_queue_tail = &this->encrypt_queue_head; this->encrypt_queue_tail = &this->encrypt_queue_head;
this->resend_queue_tail = &this->resend_queue_head; this->send_queue_tail = &this->resend_queue_head;
} }
while(whead) { while(whead) {
@ -87,8 +88,8 @@ void PacketEncoder::send_packet_acknowledge(uint16_t pid, bool low) {
char buffer[2]; char buffer[2];
le2be16(pid, buffer); le2be16(pid, buffer);
auto pflags = PacketFlag::Unencrypted | PacketFlag::NewProtocol; auto pflags = protocol::PacketFlag::Unencrypted | protocol::PacketFlag::NewProtocol;
this->send_packet(low ? protocol::PacketType::ACK_LOW : protocol::PacketType::ACK, (PacketFlag::PacketFlag) pflags, buffer, 2); this->send_packet(low ? protocol::PacketType::ACK_LOW : protocol::PacketType::ACK, (protocol::PacketFlag::PacketFlag) pflags, buffer, 2);
} }
@ -101,7 +102,7 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
size_t data_length{command.length()}; size_t data_length{command.length()};
uint8_t head_pflags{0}; uint8_t head_pflags{0};
PacketType ptype{low ? PacketType::COMMAND_LOW : PacketType::COMMAND}; protocol::PacketType ptype{low ? protocol::PacketType::COMMAND_LOW : protocol::PacketType::COMMAND};
protocol::OutgoingServerPacket *packets_head{nullptr}; protocol::OutgoingServerPacket *packets_head{nullptr};
protocol::OutgoingServerPacket **packets_tail{&packets_head}; protocol::OutgoingServerPacket **packets_tail{&packets_head};
@ -123,19 +124,19 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
data_buffer = (char*) compressed_buffer; data_buffer = (char*) compressed_buffer;
own_data_buffer_ptr = compressed_buffer; own_data_buffer_ptr = compressed_buffer;
data_length = compressed_size; data_length = compressed_size;
head_pflags |= PacketFlag::Compressed; head_pflags |= protocol::PacketFlag::Compressed;
} else { } else {
::free(compressed_buffer); ::free(compressed_buffer);
} }
} }
uint8_t ptype_and_flags{(uint8_t) ((uint8_t) ptype | (uint8_t) PacketFlag::NewProtocol)}; uint8_t ptype_and_flags{(uint8_t) ((uint8_t) ptype | (uint8_t) protocol::PacketFlag::NewProtocol)};
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);
while(true) { while(true) {
auto bytes = min(chunk_size, data_length); auto bytes = std::min(chunk_size, data_length);
auto packet = protocol::allocate_outgoing_packet(bytes); auto packet = protocol::allocate_outgoing_packet(bytes);
packet->type_and_flags = ptype_and_flags; packet->type_and_flags = ptype_and_flags;
memcpy(packet->payload, data_buffer, bytes); memcpy(packet->payload, data_buffer, bytes);
@ -145,12 +146,12 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
data_length -= bytes; data_length -= bytes;
if(data_length == 0) { if(data_length == 0) {
packet->type_and_flags |= PacketFlag::Fragmented; packet->type_and_flags |= protocol::PacketFlag::Fragmented;
break; break;
} }
data_buffer += bytes; data_buffer += bytes;
} }
packets_head->type_and_flags |= PacketFlag::Fragmented; packets_head->type_and_flags |= protocol::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;
@ -163,20 +164,19 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
{ {
std::lock_guard id_lock{this->packet_id_mutex}; std::lock_guard id_lock{this->packet_id_mutex};
{
uint32_t full_id;
auto head = packets_head;
while(head) {
full_id = this->packet_id_manager.generate_full_id(ptype);
head->set_packet_id(full_id & 0xFFFFU); uint32_t full_id;
head->generation = full_id >> 16U; auto head = packets_head;
while(head) {
full_id = this->packet_id_manager.generate_full_id(ptype);
/* loss stats (In order required so we're using the this->packet_id_mutex) */ head->set_packet_id(full_id & 0xFFFFU);
this->packet_statistics_->send_command(head->packet_type(), full_id); head->generation = full_id >> 16U;
head = head->next; /* loss stats (In order required so we're using the this->packet_id_mutex) */
} this->packet_statistics_->send_command(head->packet_type(), full_id);
head = head->next;
} }
} }
packets_head->type_and_flags |= head_pflags; packets_head->type_and_flags |= head_pflags;
@ -200,10 +200,11 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
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->next == packets_tail) if(&head->next == packets_tail) {
this->acknowledge_manager_.process_packet(ptype, full_packet_id, head, std::move(ack_listener)); this->acknowledge_manager_.process_packet(ptype, full_packet_id, head, std::move(ack_listener));
else } else {
this->acknowledge_manager_.process_packet(ptype, full_packet_id, head, nullptr); this->acknowledge_manager_.process_packet(ptype, full_packet_id, head, nullptr);
}
head = head->next; head = head->next;
} }
@ -222,7 +223,7 @@ void PacketEncoder::send_command(const std::string_view &command, bool low, std:
} }
void PacketEncoder::encrypt_pending_packets() { void PacketEncoder::encrypt_pending_packets() {
OutgoingServerPacket* packets_head; protocol::OutgoingServerPacket* packets_head;
{ {
std::lock_guard wlock{this->write_queue_mutex}; std::lock_guard wlock{this->write_queue_mutex};
packets_head = this->encrypt_queue_head; packets_head = this->encrypt_queue_head;
@ -230,36 +231,39 @@ void PacketEncoder::encrypt_pending_packets() {
this->encrypt_queue_tail = &this->encrypt_queue_head; this->encrypt_queue_tail = &this->encrypt_queue_head;
} }
if(!packets_head) if(!packets_head) {
return; return;
}
auto packet = packets_head; auto packet = packets_head;
auto packet_tail = packet; auto packet_tail = packet;
while(packet) { while(packet) {
this->prepare_outgoing_packet(packet); this->prepare_outgoing_packet(packet);
packet = packet->next; packet = packet->next;
if(packet)
if(packet) {
packet_tail = packet; packet_tail = packet;
}
} }
{ {
std::lock_guard wlock{this->write_queue_mutex}; std::lock_guard wlock{this->write_queue_mutex};
*this->resend_queue_tail = packets_head; *this->send_queue_tail = packets_head;
this->resend_queue_tail = &packet_tail->next; this->send_queue_tail = &packet_tail->next;
} }
} }
bool PacketEncoder::prepare_outgoing_packet(ts::protocol::OutgoingServerPacket *packet) { bool PacketEncoder::prepare_outgoing_packet(ts::protocol::OutgoingServerPacket *packet) {
if(packet->type_and_flags & PacketFlag::Unencrypted) { if(packet->type_and_flags & protocol::PacketFlag::Unencrypted) {
this->crypt_handler_->write_default_mac(packet->mac); this->crypt_handler_->write_default_mac(packet->mac);
} else { } else {
CryptHandler::key_t crypt_key{}; connection::CryptHandler::key_t crypt_key{};
CryptHandler::nonce_t crypt_nonce{}; connection::CryptHandler::nonce_t crypt_nonce{};
std::string error{}; std::string error{};
if(!this->crypt_handler_->encryption_initialized()) { if(!this->crypt_handler_->encryption_initialized()) {
crypt_key = CryptHandler::kDefaultKey; crypt_key = connection::CryptHandler::kDefaultKey;
crypt_nonce = CryptHandler::kDefaultNonce; crypt_nonce = connection::CryptHandler::kDefaultNonce;
} else { } else {
if(!this->crypt_handler_->generate_key_nonce(false, (uint8_t) packet->packet_type(), packet->packet_id(), packet->generation, crypt_key, crypt_nonce)) { if(!this->crypt_handler_->generate_key_nonce(false, (uint8_t) packet->packet_type(), packet->packet_id(), packet->generation, crypt_key, crypt_nonce)) {
this->callback_crypt_error(this->callback_data, CryptError::KEY_GENERATION_FAILED, ""); this->callback_crypt_error(this->callback_data, CryptError::KEY_GENERATION_FAILED, "");
@ -267,7 +271,7 @@ bool PacketEncoder::prepare_outgoing_packet(ts::protocol::OutgoingServerPacket *
} }
} }
auto crypt_result = this->crypt_handler_->encrypt((char*) packet->packet_data() + ServerPacketP::kHeaderOffset, ServerPacketP::kHeaderLength, auto crypt_result = this->crypt_handler_->encrypt((char*) packet->packet_data() + protocol::ServerPacketP::kHeaderOffset, protocol::ServerPacketP::kHeaderLength,
packet->payload, packet->payload_size, packet->payload, packet->payload_size,
packet->mac, packet->mac,
crypt_key, crypt_nonce, error); crypt_key, crypt_nonce, error);
@ -286,12 +290,12 @@ PacketEncoder::BufferPopResult PacketEncoder::pop_write_buffer(protocol::Outgoin
if(this->resend_queue_head) { if(this->resend_queue_head) {
result = this->resend_queue_head; result = this->resend_queue_head;
if(result->next) { if(result->next) {
assert(this->resend_queue_tail != &result->next); assert(this->send_queue_tail != &result->next);
this->resend_queue_head = result->next; this->resend_queue_head = result->next;
} else { } else {
assert(this->resend_queue_tail == &result->next); assert(this->send_queue_tail == &result->next);
this->resend_queue_head = nullptr; this->resend_queue_head = nullptr;
this->resend_queue_tail = &this->resend_queue_head; this->send_queue_tail = &this->resend_queue_head;
} }
} else if(this->encrypt_queue_head) { } else if(this->encrypt_queue_head) {
result = this->encrypt_queue_head; result = this->encrypt_queue_head;
@ -311,8 +315,10 @@ PacketEncoder::BufferPopResult PacketEncoder::pop_write_buffer(protocol::Outgoin
more_packets = this->resend_queue_head != nullptr || this->encrypt_queue_head != nullptr; more_packets = this->resend_queue_head != nullptr || this->encrypt_queue_head != nullptr;
} }
if(need_prepare_packet) if(need_prepare_packet) {
this->prepare_outgoing_packet(result); this->prepare_outgoing_packet(result);
}
return more_packets ? BufferPopResult::MORE_AVAILABLE : BufferPopResult::DRAINED; return more_packets ? BufferPopResult::MORE_AVAILABLE : BufferPopResult::DRAINED;
} }
@ -325,20 +331,22 @@ void PacketEncoder::execute_resend(const std::chrono::system_clock::time_point &
if(!buffers.empty()) { if(!buffers.empty()) {
size_t send_count{0}; size_t send_count{0};
{ {
lock_guard wlock{this->write_queue_mutex}; std::lock_guard wlock{this->write_queue_mutex};
for(auto& buffer : buffers) { for(auto& buffer : buffers) {
auto packet = (protocol::OutgoingServerPacket*) buffer->packet_ptr; auto packet = (protocol::OutgoingServerPacket*) buffer->packet_ptr;
/* Test if the packet is still in the write/enqueue queue */ /* Test if the packet is still in the write/enqueue queue */
if(packet->next) if(packet->next) {
continue; continue;
}
if(&packet->next == this->encrypt_queue_tail || &packet->next == this->resend_queue_tail) if(&packet->next == this->encrypt_queue_tail || &packet->next == this->send_queue_tail) {
continue; continue;
}
packet->ref(); /* for the write queue again */ packet->ref(); /* for the write queue again */
*this->resend_queue_tail = packet; *this->send_queue_tail = packet;
this->resend_queue_tail = &packet->next; this->send_queue_tail = &packet->next;
send_count++; send_count++;
buffer->resend_count++; buffer->resend_count++;
@ -352,7 +360,7 @@ void PacketEncoder::execute_resend(const std::chrono::system_clock::time_point &
} }
} }
bool PacketEncoder::wait_empty_write_and_prepare_queue(chrono::time_point<chrono::system_clock> until) { bool PacketEncoder::wait_empty_write_and_prepare_queue(std::chrono::time_point<std::chrono::system_clock> until) {
while(true) { while(true) {
{ {
std::lock_guard wlock{this->write_queue_mutex}; std::lock_guard wlock{this->write_queue_mutex};

View File

@ -75,7 +75,7 @@ namespace ts::server::server::udp {
spin_mutex write_queue_mutex{}; spin_mutex write_queue_mutex{};
protocol::OutgoingServerPacket* resend_queue_head{nullptr}; protocol::OutgoingServerPacket* resend_queue_head{nullptr};
protocol::OutgoingServerPacket** resend_queue_tail{&resend_queue_head}; protocol::OutgoingServerPacket** send_queue_tail{&resend_queue_head};
protocol::OutgoingServerPacket* encrypt_queue_head{nullptr}; protocol::OutgoingServerPacket* encrypt_queue_head{nullptr};
protocol::OutgoingServerPacket** encrypt_queue_tail{&encrypt_queue_head}; protocol::OutgoingServerPacket** encrypt_queue_tail{&encrypt_queue_head};

View File

@ -47,8 +47,9 @@ void ServerCommandExecutor::enqueue_command_execution(ReassembledCommand *comman
if(!command_handling_scheduled) { if(!command_handling_scheduled) {
auto voice_server = this->client->getVoiceServer(); auto voice_server = this->client->getVoiceServer();
if(voice_server) if(voice_server) {
voice_server->schedule_command_handling(&*client); voice_server->schedule_command_handling(&*client);
}
} }
} }

View File

@ -18,7 +18,7 @@ void WebClient::handleMessageWrite(int fd, short, void *) {
auto buffer = this->queue_write[0]; auto buffer = this->queue_write[0];
this->queue_write.pop_front(); this->queue_write.pop_front();
auto written = send(fd, buffer.data_ptr(), buffer.length(), MSG_NOSIGNAL); auto written = send(fd, buffer.data_ptr(), buffer.length(), MSG_NOSIGNAL | MSG_DONTWAIT);
if(written == -1) { if(written == -1) {
buffer_lock.unlock(); buffer_lock.unlock();
@ -66,7 +66,7 @@ void WebClient::handleMessageRead(int fd, short, void *) {
size_t buffer_length = 1024 * 4; size_t buffer_length = 1024 * 4;
uint8_t buffer[buffer_length]; uint8_t buffer[buffer_length];
auto length = read(fd, buffer, buffer_length); auto length = recv(fd, buffer, buffer_length, MSG_NOSIGNAL | MSG_DONTWAIT);
if(length <= 0){ if(length <= 0){
if(errno == EINTR || errno == EAGAIN) if(errno == EINTR || errno == EAGAIN)
; ;