From 9e268ea4dc0f3c21f38e840db2473d5f8abceeeb Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 12 Jan 2025 16:03:41 +0100 Subject: [PATCH] GDB stub progress --- src/common/network/address.hpp | 8 +++ src/common/network/socket.cpp | 36 ++++++---- src/common/network/socket.hpp | 21 +++--- src/common/network/tcp_client_socket.cpp | 45 ++++++++++--- src/common/network/tcp_client_socket.hpp | 2 +- src/common/network/udp_socket.cpp | 26 +++++--- src/common/network/udp_socket.hpp | 2 +- src/gdb-stub/gdb_stub.cpp | 65 ++++++++++++++++--- src/windows-emulator/devices/afd_endpoint.cpp | 4 +- 9 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/common/network/address.hpp b/src/common/network/address.hpp index dbf11e18..d42604b0 100644 --- a/src/common/network/address.hpp +++ b/src/common/network/address.hpp @@ -48,6 +48,14 @@ namespace network address(const sockaddr_in6& addr); address(const sockaddr* addr, socklen_t length); + address(const address&) = default; + address(address&&) noexcept = default; + + address& operator=(const address&) = default; + address& operator=(address&&) noexcept = default; + + ~address() = default; + void set_ipv4(uint32_t ip); void set_ipv4(const in_addr& addr); void set_ipv6(const in6_addr& addr); diff --git a/src/common/network/socket.cpp b/src/common/network/socket.cpp index 3339d3f4..1e057da7 100644 --- a/src/common/network/socket.cpp +++ b/src/common/network/socket.cpp @@ -31,7 +31,7 @@ namespace network socket::~socket() { - this->release(); + this->close(); } socket::socket(socket&& obj) noexcept @@ -43,7 +43,7 @@ namespace network { if (this != &obj) { - this->release(); + this->close(); this->socket_ = obj.socket_; obj.socket_ = INVALID_SOCKET; @@ -53,15 +53,20 @@ namespace network } socket::operator bool() const + { + return this->is_valid(); + } + + bool socket::is_valid() const { return this->socket_ != INVALID_SOCKET; } - void socket::release() + void socket::close() { if (this->socket_ != INVALID_SOCKET) { - closesocket(this->socket_); + ::closesocket(this->socket_); this->socket_ = INVALID_SOCKET; } } @@ -90,7 +95,7 @@ namespace network #endif } - bool socket::sleep(const std::chrono::milliseconds timeout) const + bool socket::sleep(const std::chrono::milliseconds timeout, const bool in_poll) const { /*fd_set fdr; FD_ZERO(&fdr); @@ -119,13 +124,13 @@ namespace network std::vector sockets{}; sockets.push_back(this); - return sleep_sockets(sockets, timeout); + return sleep_sockets(sockets, timeout, in_poll); } - bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point) const + bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point, const bool in_poll) const { const auto duration = time_point - std::chrono::high_resolution_clock::now(); - return this->sleep(std::chrono::duration_cast(duration)); + return this->sleep(std::chrono::duration_cast(duration), in_poll); } SOCKET socket::get_socket() const @@ -167,7 +172,13 @@ namespace network return address->get_addr().sa_family; } - bool socket::sleep_sockets(const std::span& sockets, const std::chrono::milliseconds timeout) + bool socket::is_ready(const bool in_poll) const + { + return this->is_valid() && is_socket_ready(this->socket_, in_poll); + } + + bool socket::sleep_sockets(const std::span& sockets, const std::chrono::milliseconds timeout, + const bool in_poll) { std::vector pfds{}; pfds.resize(sockets.size()); @@ -178,7 +189,7 @@ namespace network const auto& socket = sockets[i]; pfd.fd = socket->get_socket(); - pfd.events = POLLIN; + pfd.events = in_poll ? POLLIN : POLLOUT; pfd.revents = 0; } @@ -223,9 +234,10 @@ namespace network } bool socket::sleep_sockets_until(const std::span& sockets, - const std::chrono::high_resolution_clock::time_point time_point) + const std::chrono::high_resolution_clock::time_point time_point, + const bool in_poll) { const auto duration = time_point - std::chrono::high_resolution_clock::now(); - return sleep_sockets(sockets, std::chrono::duration_cast(duration)); + return sleep_sockets(sockets, std::chrono::duration_cast(duration), in_poll); } } diff --git a/src/common/network/socket.hpp b/src/common/network/socket.hpp index 4696fb88..957c9c1b 100644 --- a/src/common/network/socket.hpp +++ b/src/common/network/socket.hpp @@ -10,7 +10,7 @@ using send_size = int; #define GET_SOCKET_ERROR() (WSAGetLastError()) #define poll WSAPoll -#define SOCK_WOULDBLOCK WSAEWOULDBLOCK +#define SERR(x) (WSA##x) #define SHUT_RDWR SD_BOTH #else using SOCKET = int; @@ -19,7 +19,7 @@ using send_size = size_t; #define SOCKET_ERROR (-1) #define GET_SOCKET_ERROR() (errno) #define closesocket close -#define SOCK_WOULDBLOCK EWOULDBLOCK +#define SERR(x) (x) #endif namespace network @@ -42,14 +42,16 @@ namespace network operator bool() const; + bool is_valid() const; + bool bind(const address& target); bool set_blocking(bool blocking); static bool set_blocking(SOCKET s, bool blocking); static constexpr bool socket_is_ready = true; - bool sleep(std::chrono::milliseconds timeout) const; - bool sleep_until(std::chrono::high_resolution_clock::time_point time_point) const; + bool sleep(std::chrono::milliseconds timeout, bool in_poll = true) const; + bool sleep_until(std::chrono::high_resolution_clock::time_point time_point, bool in_poll = true) const; SOCKET get_socket() const; uint16_t get_port() const; @@ -57,15 +59,18 @@ namespace network int get_address_family() const; - static bool sleep_sockets(const std::span& sockets, std::chrono::milliseconds timeout); + bool is_ready(bool in_poll) const; + + static bool sleep_sockets(const std::span& sockets, std::chrono::milliseconds timeout, + bool in_poll); static bool sleep_sockets_until(const std::span& sockets, - std::chrono::high_resolution_clock::time_point time_point); + std::chrono::high_resolution_clock::time_point time_point, bool in_poll); static bool is_socket_ready(SOCKET s, bool in_poll); + void close(); + private: SOCKET socket_ = INVALID_SOCKET; - - void release(); }; } diff --git a/src/common/network/tcp_client_socket.cpp b/src/common/network/tcp_client_socket.cpp index 9739b394..efb4ad34 100644 --- a/src/common/network/tcp_client_socket.cpp +++ b/src/common/network/tcp_client_socket.cpp @@ -26,27 +26,52 @@ namespace network bool tcp_client_socket::send(const void* data, const size_t size) const { - const auto res = ::send(this->get_socket(), static_cast(data), static_cast(size), 0); - return static_cast(res) == size; + return this->send(std::string_view(static_cast(data), size)); } - bool tcp_client_socket::send(const std::string_view data) const + bool tcp_client_socket::send(std::string_view data) const { - return this->send(data.data(), data.size()); + while (!data.empty()) + { + const auto res = ::send(this->get_socket(), data.data(), static_cast(data.size()), 0); + if (res < 0) + { + if (GET_SOCKET_ERROR() != SERR(EWOULDBLOCK)) + { + break; + } + + this->sleep(std::chrono::milliseconds(10), true); + continue; + } + + if (static_cast(res) > data.size()) + { + break; + } + + data = data.substr(res); + } + + return data.empty(); } - bool tcp_client_socket::receive(std::string& data) const + std::optional tcp_client_socket::receive() { char buffer[0x2000]; const auto result = recv(this->get_socket(), buffer, static_cast(sizeof(buffer)), 0); - if (result == SOCKET_ERROR) + if (result > 0) { - return false; + return std::string(buffer, result); } - data.assign(buffer, buffer + result); - return true; + if (result == 0 || (result < 0 && GET_SOCKET_ERROR() == SERR(ECONNRESET))) + { + this->close(); + } + + return std::nullopt; } std::optional
tcp_client_socket::get_target() const @@ -69,6 +94,6 @@ namespace network } const auto error = GET_SOCKET_ERROR(); - return error == SOCK_WOULDBLOCK; + return error == SERR(EWOULDBLOCK); } } diff --git a/src/common/network/tcp_client_socket.hpp b/src/common/network/tcp_client_socket.hpp index e5b586a1..ec032601 100644 --- a/src/common/network/tcp_client_socket.hpp +++ b/src/common/network/tcp_client_socket.hpp @@ -21,7 +21,7 @@ namespace network [[maybe_unused]] bool send(const void* data, size_t size) const; [[maybe_unused]] bool send(std::string_view data) const; - bool receive(std::string& data) const; + std::optional receive(); std::optional
get_target() const; diff --git a/src/common/network/udp_socket.cpp b/src/common/network/udp_socket.cpp index 99c6e9e6..379ccbab 100644 --- a/src/common/network/udp_socket.cpp +++ b/src/common/network/udp_socket.cpp @@ -9,29 +9,39 @@ namespace network bool udp_socket::send(const address& target, const void* data, const size_t size) const { - const auto res = sendto(this->get_socket(), static_cast(data), static_cast(size), 0, - &target.get_addr(), target.get_size()); - return static_cast(res) == size; + return this->send(target, std::string_view(static_cast(data), size)); } bool udp_socket::send(const address& target, const std::string_view data) const { - return this->send(target, data.data(), data.size()); + while (true) + { + const auto res = sendto(this->get_socket(), data.data(), static_cast(data.size()), 0, + &target.get_addr(), target.get_size()); + + if (res < 0 && GET_SOCKET_ERROR() == SERR(EWOULDBLOCK)) + { + this->sleep(std::chrono::milliseconds(10), true); + continue; + } + + return static_cast(res) == data.size(); + } } - bool udp_socket::receive(address& source, std::string& data) const + std::optional> udp_socket::receive() const { char buffer[0x2000]; + address source{}; auto len = source.get_max_size(); const auto result = recvfrom(this->get_socket(), buffer, static_cast(sizeof(buffer)), 0, &source.get_addr(), &len); if (result == SOCKET_ERROR) { - return false; + return std::nullopt; } - data.assign(buffer, buffer + result); - return true; + return {{source, std::string(buffer, result)}}; } } diff --git a/src/common/network/udp_socket.hpp b/src/common/network/udp_socket.hpp index 2e240728..affbe6c8 100644 --- a/src/common/network/udp_socket.hpp +++ b/src/common/network/udp_socket.hpp @@ -17,6 +17,6 @@ namespace network [[maybe_unused]] bool send(const address& target, const void* data, size_t size) const; [[maybe_unused]] bool send(const address& target, std::string_view data) const; - bool receive(address& source, std::string& data) const; + std::optional> receive() const; }; } diff --git a/src/gdb-stub/gdb_stub.cpp b/src/gdb-stub/gdb_stub.cpp index 85dd688c..4c983b83 100644 --- a/src/gdb-stub/gdb_stub.cpp +++ b/src/gdb-stub/gdb_stub.cpp @@ -21,6 +21,21 @@ namespace gdb_stub return csum; } + std::string compute_checksum_string(const std::string_view data) + { + const auto checksum = compute_checksum(data); + + std::stringstream stream{}; + stream << std::hex << checksum; + return stream.str(); + } + + bool send_packet_reply(const network::tcp_client_socket& socket, const std::string_view data) + { + const auto checksum = compute_checksum_string(data); + return socket.send("$" + std::string(data) + "#" + checksum); + } + network::tcp_client_socket accept_client(const network::address& bind_address) { network::tcp_server_socket server{bind_address.get_family()}; @@ -102,27 +117,61 @@ namespace gdb_stub } } }; + + void read_from_socket(packet_queue& queue, network::tcp_client_socket& client) + { + while (client.is_ready(true)) + { + auto packet = client.receive(); + if (packet) + { + queue.enqueue(std::move(*packet)); + } + } + } + + void handle_command(const uint8_t command, const std::string_view data) + { + switch (command) + { + case 'q': + break; + } + } + + void process_packet(const std::string_view packet) + { + if (packet.empty()) + { + return; + } + + const auto command = packet.front(); + handle_command(command, packet.substr(1)); + } } bool run_gdb_stub(const network::address& bind_address) { - const auto client = accept_client(bind_address); + packet_queue queue{}; + + auto client = accept_client(bind_address); if (!client) { return false; } - packet_queue queue{}; + client.set_blocking(false); while (true) { - std::string packet{}; - if (!client.receive(packet)) - { - break; - } + read_from_socket(queue, client); - queue.enqueue(packet); + while (!queue.packets.empty()) + { + process_packet(queue.packets.front()); + queue.packets.pop(); + } } return true; diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index f0ab1cb0..1a364eb4 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -457,7 +457,7 @@ namespace if (recevied_data < 0) { const auto error = GET_SOCKET_ERROR(); - if (error == SOCK_WOULDBLOCK) + if (error == SERR(EWOULDBLOCK)) { this->delay_ioctrl(c, {}, true); return STATUS_PENDING; @@ -512,7 +512,7 @@ namespace if (sent_data < 0) { const auto error = GET_SOCKET_ERROR(); - if (error == SOCK_WOULDBLOCK) + if (error == SERR(EWOULDBLOCK)) { this->delay_ioctrl(c, {}, false); return STATUS_PENDING;