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 "Connection.hpp"
#include <sys/socket.h> #include <arpa/inet.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <cerrno> #include <cerrno>
#include <fcntl.h> #include <fcntl.h>
@@ -19,34 +19,36 @@ namespace Bloom::DebugServers::Gdb
using ResponsePackets::ResponsePacket; using ResponsePackets::ResponsePacket;
void Connection::accept(int serverSocketFileDescriptor) { Connection::Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier)
int socketAddressLength = sizeof(this->socketAddress); : interruptEventNotifier(interruptEventNotifier)
{
this->socketFileDescriptor = ::accept( this->accept(serverSocketFileDescriptor);
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");
}
::fcntl( ::fcntl(
this->socketFileDescriptor, this->socketFileDescriptor.value(),
F_SETFL, 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(); this->enableReadInterrupts();
} }
void Connection::close() noexcept { Connection::~Connection() {
if (this->socketFileDescriptor > 0) { this->close();
::close(this->socketFileDescriptor); }
this->socketFileDescriptor = 0;
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() { std::vector<RawPacketType> Connection::readRawPackets() {
@@ -145,6 +147,29 @@ namespace Bloom::DebugServers::Gdb
} while (this->readSingleByte(false).value_or(0) != '+'); } 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( std::vector<unsigned char> Connection::read(
size_t bytes, size_t bytes,
bool interruptible, bool interruptible,
@@ -183,7 +208,7 @@ namespace Bloom::DebugServers::Gdb
size_t bytesToRead = (bytes > bufferSize || bytes == 0) ? bufferSize : bytes; size_t bytesToRead = (bytes > bufferSize || bytes == 0) ? bufferSize : bytes;
while ( while (
bytesToRead > 0 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); 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) { void Connection::write(const std::vector<unsigned char>& buffer) {
Logger::debug("Writing packet: " + std::string(buffer.begin(), buffer.end())); 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) { if (errno == EPIPE || errno == ECONNRESET) {
// Connection was closed // Connection was closed
throw ClientDisconnected(); throw ClientDisconnected();

View File

@@ -1,13 +1,12 @@
#pragma once #pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <netinet/in.h>
#include <queue> #include <queue>
#include <array> #include <array>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <chrono> #include <chrono>
#include "src/Helpers/EventNotifier.hpp" #include "src/Helpers/EventNotifier.hpp"
@@ -24,47 +23,30 @@ namespace Bloom::DebugServers::Gdb
class Connection class Connection
{ {
public: public:
explicit Connection(EventNotifier& interruptEventNotifier) explicit Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier);
: interruptEventNotifier(interruptEventNotifier)
{};
Connection() = delete; Connection() = delete;
Connection(const Connection&) = delete; Connection(const Connection&) = delete;
Connection& operator = (Connection&) = delete;
Connection& operator = (Connection&&) = delete;
Connection(Connection&& other) noexcept Connection(Connection&& other) noexcept
: interruptEventNotifier(other.interruptEventNotifier) : interruptEventNotifier(other.interruptEventNotifier)
, socketFileDescriptor(other.socketFileDescriptor) , socketFileDescriptor(other.socketFileDescriptor)
, epollInstance(std::move(other.epollInstance)) , epollInstance(std::move(other.epollInstance))
, readInterruptEnabled(other.readInterruptEnabled) , readInterruptEnabled(other.readInterruptEnabled)
{ {
other.socketFileDescriptor = -1; other.socketFileDescriptor = std::nullopt;
}; }
/** ~Connection();
* Accepts a connection on serverSocketFileDescriptor.
*
* @param serverSocketFileDescriptor
*/
void accept(int serverSocketFileDescriptor);
/**
* Closes the connection with the client.
*/
void close() noexcept;
/** /**
* Obtains the human readable IP address of the connected client. * Obtains the human readable IP address of the connected client.
* *
* @return * @return
*/ */
std::string getIpAddress() { [[nodiscard]] std::string getIpAddress() const;
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());
};
/** /**
* Waits for incoming data from the client and returns the raw GDB packets. * Waits for incoming data from the client and returns the raw GDB packets.
@@ -85,7 +67,7 @@ namespace Bloom::DebugServers::Gdb
} }
private: private:
int socketFileDescriptor = -1; std::optional<int> socketFileDescriptor;
EpollInstance epollInstance = EpollInstance(); EpollInstance epollInstance = EpollInstance();
@@ -99,6 +81,18 @@ namespace Bloom::DebugServers::Gdb
EventNotifier& interruptEventNotifier; EventNotifier& interruptEventNotifier;
bool readInterruptEnabled = false; 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. * Reads data from the client into a raw buffer.
* *

View File

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

View File

@@ -134,7 +134,6 @@ namespace Bloom::DebugServers::Gdb
return; return;
} }
connection->accept(this->serverSocketFileDescriptor);
Logger::info("Accepted GDP RSP connection from " + connection->getIpAddress()); Logger::info("Accepted GDP RSP connection from " + connection->getIpAddress());
this->activeDebugSession.emplace( this->activeDebugSession.emplace(
@@ -206,7 +205,7 @@ namespace Bloom::DebugServers::Gdb
return std::nullopt; 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() { std::unique_ptr<CommandPacket> GdbRspDebugServer::waitForCommandPacket() {