Files
windows-user-space-emulator/src/gdb-stub/connection_handler.cpp
2025-08-16 14:55:07 +02:00

132 lines
3.2 KiB
C++

#include "connection_handler.hpp"
#include "checksum.hpp"
#include <utils/string.hpp>
#include <thread>
using namespace std::literals;
namespace gdb_stub
{
namespace
{
bool read_from_socket(stream_processor& processor, network::tcp_client_socket& client)
{
const auto data = client.receive();
if (!data)
{
return false;
}
processor.push_stream_data(*data);
return true;
}
}
connection_handler::connection_handler(network::tcp_client_socket& client, utils::optional_function<bool()> should_stop)
: should_stop_(std::move(should_stop)),
client_(client)
{
this->client_.set_blocking(false);
this->stop_ = false;
this->output_thread_ = std::thread([this] {
this->transmission_loop(); //
});
}
connection_handler::~connection_handler()
{
this->stop_ = true;
this->condition_variable_.notify_all();
if (this->output_thread_.joinable())
{
this->output_thread_.join();
}
}
std::optional<std::string> connection_handler::get_packet()
{
while (this->client_.is_valid() && !this->processor_.has_packet() && !this->should_stop_())
{
if (!read_from_socket(this->processor_, this->client_))
{
(void)this->client_.sleep(100ms, true);
}
}
if (this->processor_.has_packet())
{
return this->processor_.get_next_packet();
}
return std::nullopt;
}
void connection_handler::send_reply(const std::string_view data)
{
const auto checksum = utils::string::to_hex_string(compute_checksum(data));
this->send_raw_data("$" + std::string(data) + "#" + checksum);
}
void connection_handler::send_raw_data(const std::string_view data)
{
{
std::lock_guard _{this->mutex_};
this->output_stream_.append(data);
}
this->condition_variable_.notify_one();
}
bool connection_handler::should_stop() const
{
return this->stop_ || !this->client_.is_valid();
}
void connection_handler::close() const
{
this->client_.close();
}
void connection_handler::await_transmission(const std::function<void()>& handler)
{
std::unique_lock lock{this->mutex_};
const auto can_run = [this] {
return this->should_stop() //
|| !this->output_stream_.empty();
};
const auto run = this->condition_variable_.wait_for(lock, 100ms, can_run);
if (run && !this->should_stop())
{
handler();
}
}
std::string connection_handler::get_next_data_to_transmit()
{
std::string transmit_data{};
this->await_transmission([&] {
transmit_data = std::move(this->output_stream_);
this->output_stream_ = {};
});
return transmit_data;
}
void connection_handler::transmission_loop()
{
while (!this->should_stop())
{
const auto data = this->get_next_data_to_transmit();
(void)this->client_.send(data);
}
}
}