Tidied GDB Connection class and made it adhere to the RAII approach

This commit is contained in:
Nav
2022-03-29 14:54:49 +01:00
parent a743381d8c
commit 97776f12e0
4 changed files with 72 additions and 54 deletions

View File

@@ -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();

View File

@@ -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.
*

View File

@@ -10,6 +10,6 @@ namespace Bloom::DebugServers::Gdb
{}
void DebugSession::terminate() {
this->connection.close();
}
}

View File

@@ -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() {