diff --git a/src/DebugServers/GdbRsp/Connection.cpp b/src/DebugServers/GdbRsp/Connection.cpp index 4eb6ccfb..cb547ec4 100644 --- a/src/DebugServers/GdbRsp/Connection.cpp +++ b/src/DebugServers/GdbRsp/Connection.cpp @@ -1,6 +1,6 @@ #include "Connection.hpp" -#include +#include #include #include #include @@ -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(&(this->socketAddress)), - reinterpret_cast(&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(EpollEvent::READ_READY)); + this->epollInstance.addEntry( + this->socketFileDescriptor.value(), + static_cast(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 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 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(&(this->socketAddress)), + reinterpret_cast(&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 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& 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(); diff --git a/src/DebugServers/GdbRsp/Connection.hpp b/src/DebugServers/GdbRsp/Connection.hpp index 17c9f001..146ac362 100644 --- a/src/DebugServers/GdbRsp/Connection.hpp +++ b/src/DebugServers/GdbRsp/Connection.hpp @@ -1,13 +1,12 @@ #pragma once +#include +#include #include #include #include -#include #include #include -#include -#include #include #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 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 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. * diff --git a/src/DebugServers/GdbRsp/DebugSession.cpp b/src/DebugServers/GdbRsp/DebugSession.cpp index 9fc5b5de..169b8774 100644 --- a/src/DebugServers/GdbRsp/DebugSession.cpp +++ b/src/DebugServers/GdbRsp/DebugSession.cpp @@ -10,6 +10,6 @@ namespace Bloom::DebugServers::Gdb {} void DebugSession::terminate() { - this->connection.close(); + } } diff --git a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp index fb60c87e..d636faf2 100644 --- a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp +++ b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp @@ -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(*(this->interruptEventNotifier)); + return std::make_optional(this->serverSocketFileDescriptor, *(this->interruptEventNotifier)); } std::unique_ptr GdbRspDebugServer::waitForCommandPacket() {