Tidied GDB Connection class and made it adhere to the RAII approach
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#include "Connection.hpp"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
@@ -19,34 +19,36 @@ namespace Bloom::DebugServers::Gdb
|
||||
|
||||
using ResponsePackets::ResponsePacket;
|
||||
|
||||
void Connection::accept(int serverSocketFileDescriptor) {
|
||||
int socketAddressLength = sizeof(this->socketAddress);
|
||||
|
||||
this->socketFileDescriptor = ::accept(
|
||||
serverSocketFileDescriptor,
|
||||
reinterpret_cast<sockaddr*>(&(this->socketAddress)),
|
||||
reinterpret_cast<socklen_t*>(&socketAddressLength)
|
||||
);
|
||||
|
||||
if (this->socketFileDescriptor == -1) {
|
||||
throw Exception("Failed to accept GDB Remote Serial Protocol connection");
|
||||
}
|
||||
Connection::Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier)
|
||||
: interruptEventNotifier(interruptEventNotifier)
|
||||
{
|
||||
this->accept(serverSocketFileDescriptor);
|
||||
|
||||
::fcntl(
|
||||
this->socketFileDescriptor,
|
||||
this->socketFileDescriptor.value(),
|
||||
F_SETFL,
|
||||
::fcntl(this->socketFileDescriptor, F_GETFL, 0) | O_NONBLOCK
|
||||
::fcntl(this->socketFileDescriptor.value(), F_GETFL, 0) | O_NONBLOCK
|
||||
);
|
||||
|
||||
this->epollInstance.addEntry(this->socketFileDescriptor, static_cast<std::uint16_t>(EpollEvent::READ_READY));
|
||||
this->epollInstance.addEntry(
|
||||
this->socketFileDescriptor.value(),
|
||||
static_cast<std::uint16_t>(EpollEvent::READ_READY)
|
||||
);
|
||||
this->enableReadInterrupts();
|
||||
}
|
||||
|
||||
void Connection::close() noexcept {
|
||||
if (this->socketFileDescriptor > 0) {
|
||||
::close(this->socketFileDescriptor);
|
||||
this->socketFileDescriptor = 0;
|
||||
Connection::~Connection() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
std::string Connection::getIpAddress() const {
|
||||
std::array<char, INET_ADDRSTRLEN> ipAddress = {};
|
||||
|
||||
if (::inet_ntop(AF_INET, &(socketAddress.sin_addr), ipAddress.data(), INET_ADDRSTRLEN) == nullptr) {
|
||||
throw Exception("Failed to convert client IP address to text form.");
|
||||
}
|
||||
|
||||
return std::string(ipAddress.data());
|
||||
}
|
||||
|
||||
std::vector<RawPacketType> Connection::readRawPackets() {
|
||||
@@ -145,6 +147,29 @@ namespace Bloom::DebugServers::Gdb
|
||||
} while (this->readSingleByte(false).value_or(0) != '+');
|
||||
}
|
||||
|
||||
void Connection::accept(int serverSocketFileDescriptor) {
|
||||
int socketAddressLength = sizeof(this->socketAddress);
|
||||
|
||||
const auto socketFileDescriptor = ::accept(
|
||||
serverSocketFileDescriptor,
|
||||
reinterpret_cast<sockaddr*>(&(this->socketAddress)),
|
||||
reinterpret_cast<socklen_t*>(&socketAddressLength)
|
||||
);
|
||||
|
||||
if (socketFileDescriptor < 0) {
|
||||
throw Exception("Failed to accept GDB Remote Serial Protocol connection");
|
||||
}
|
||||
|
||||
this->socketFileDescriptor = socketFileDescriptor;
|
||||
}
|
||||
|
||||
void Connection::close() noexcept {
|
||||
if (this->socketFileDescriptor.value_or(-1) >= 0) {
|
||||
::close(this->socketFileDescriptor.value());
|
||||
this->socketFileDescriptor = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Connection::read(
|
||||
size_t bytes,
|
||||
bool interruptible,
|
||||
@@ -183,7 +208,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
size_t bytesToRead = (bytes > bufferSize || bytes == 0) ? bufferSize : bytes;
|
||||
while (
|
||||
bytesToRead > 0
|
||||
&& (bytesRead = ::read(this->socketFileDescriptor, buffer.data(), bytesToRead)) > 0
|
||||
&& (bytesRead = ::read(this->socketFileDescriptor.value(), buffer.data(), bytesToRead)) > 0
|
||||
) {
|
||||
output.insert(output.end(), buffer.begin(), buffer.begin() + bytesRead);
|
||||
|
||||
@@ -215,7 +240,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
|
||||
void Connection::write(const std::vector<unsigned char>& buffer) {
|
||||
Logger::debug("Writing packet: " + std::string(buffer.begin(), buffer.end()));
|
||||
if (::write(this->socketFileDescriptor, buffer.data(), buffer.size()) == -1) {
|
||||
if (::write(this->socketFileDescriptor.value(), buffer.data(), buffer.size()) == -1) {
|
||||
if (errno == EPIPE || errno == ECONNRESET) {
|
||||
// Connection was closed
|
||||
throw ClientDisconnected();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <netinet/in.h>
|
||||
#include <queue>
|
||||
#include <array>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <chrono>
|
||||
|
||||
#include "src/Helpers/EventNotifier.hpp"
|
||||
@@ -24,47 +23,30 @@ namespace Bloom::DebugServers::Gdb
|
||||
class Connection
|
||||
{
|
||||
public:
|
||||
explicit Connection(EventNotifier& interruptEventNotifier)
|
||||
: interruptEventNotifier(interruptEventNotifier)
|
||||
{};
|
||||
explicit Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier);
|
||||
|
||||
Connection() = delete;
|
||||
Connection(const Connection&) = delete;
|
||||
Connection& operator = (Connection&) = delete;
|
||||
Connection& operator = (Connection&&) = delete;
|
||||
|
||||
Connection(Connection&& other) noexcept
|
||||
: interruptEventNotifier(other.interruptEventNotifier)
|
||||
, socketFileDescriptor(other.socketFileDescriptor)
|
||||
, epollInstance(std::move(other.epollInstance))
|
||||
, readInterruptEnabled(other.readInterruptEnabled)
|
||||
{
|
||||
other.socketFileDescriptor = -1;
|
||||
};
|
||||
other.socketFileDescriptor = std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a connection on serverSocketFileDescriptor.
|
||||
*
|
||||
* @param serverSocketFileDescriptor
|
||||
*/
|
||||
void accept(int serverSocketFileDescriptor);
|
||||
|
||||
/**
|
||||
* Closes the connection with the client.
|
||||
*/
|
||||
void close() noexcept;
|
||||
~Connection();
|
||||
|
||||
/**
|
||||
* Obtains the human readable IP address of the connected client.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string getIpAddress() {
|
||||
std::array<char, INET_ADDRSTRLEN> ipAddress = {};
|
||||
|
||||
if (::inet_ntop(AF_INET, &(socketAddress.sin_addr), ipAddress.data(), INET_ADDRSTRLEN) == nullptr) {
|
||||
throw Exceptions::Exception("Failed to convert client IP address to text form.");
|
||||
}
|
||||
|
||||
return std::string(ipAddress.data());
|
||||
};
|
||||
[[nodiscard]] std::string getIpAddress() const;
|
||||
|
||||
/**
|
||||
* Waits for incoming data from the client and returns the raw GDB packets.
|
||||
@@ -85,7 +67,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
}
|
||||
|
||||
private:
|
||||
int socketFileDescriptor = -1;
|
||||
std::optional<int> socketFileDescriptor;
|
||||
|
||||
EpollInstance epollInstance = EpollInstance();
|
||||
|
||||
@@ -99,6 +81,18 @@ namespace Bloom::DebugServers::Gdb
|
||||
EventNotifier& interruptEventNotifier;
|
||||
bool readInterruptEnabled = false;
|
||||
|
||||
/**
|
||||
* Accepts a connection on serverSocketFileDescriptor.
|
||||
*
|
||||
* @param serverSocketFileDescriptor
|
||||
*/
|
||||
void accept(int serverSocketFileDescriptor);
|
||||
|
||||
/**
|
||||
* Closes the connection with the client.
|
||||
*/
|
||||
void close() noexcept;
|
||||
|
||||
/**
|
||||
* Reads data from the client into a raw buffer.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,6 @@ namespace Bloom::DebugServers::Gdb
|
||||
{}
|
||||
|
||||
void DebugSession::terminate() {
|
||||
this->connection.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,6 @@ namespace Bloom::DebugServers::Gdb
|
||||
return;
|
||||
}
|
||||
|
||||
connection->accept(this->serverSocketFileDescriptor);
|
||||
Logger::info("Accepted GDP RSP connection from " + connection->getIpAddress());
|
||||
|
||||
this->activeDebugSession.emplace(
|
||||
@@ -206,7 +205,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional<Connection>(*(this->interruptEventNotifier));
|
||||
return std::make_optional<Connection>(this->serverSocketFileDescriptor, *(this->interruptEventNotifier));
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandPacket> GdbRspDebugServer::waitForCommandPacket() {
|
||||
|
||||
Reference in New Issue
Block a user