2021-10-02 17:39:27 +01:00
|
|
|
#include "Connection.hpp"
|
|
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
#include <arpa/inet.h>
|
2022-04-05 22:37:00 +01:00
|
|
|
#include <unistd.h>
|
2021-06-22 23:52:31 +01:00
|
|
|
#include <cerrno>
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <fcntl.h>
|
2022-11-17 21:00:45 +00:00
|
|
|
#include <algorithm>
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
#include "Exceptions/ClientDisconnected.hpp"
|
2022-11-18 20:26:20 +00:00
|
|
|
#include "Exceptions/DebugServerInterrupted.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
#include "Exceptions/ClientCommunicationError.hpp"
|
2022-11-18 20:26:20 +00:00
|
|
|
|
2021-10-02 17:39:27 +01:00
|
|
|
#include "src/Exceptions/Exception.hpp"
|
2024-11-28 21:49:03 +00:00
|
|
|
#include "src/Exceptions/InternalFatalErrorException.hpp"
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2021-10-02 17:39:27 +01:00
|
|
|
#include "src/Logger/Logger.hpp"
|
2023-05-07 16:45:04 +01:00
|
|
|
#include "src/Services/StringService.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
namespace DebugServer::Gdb
|
2022-02-05 15:32:08 +00:00
|
|
|
{
|
|
|
|
|
using namespace Exceptions;
|
2023-08-13 15:47:51 +01:00
|
|
|
using namespace ::Exceptions;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-03-27 19:43:20 +01:00
|
|
|
using ResponsePackets::ResponsePacket;
|
|
|
|
|
|
2022-04-15 22:05:50 +01:00
|
|
|
Connection::Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier)
|
2022-03-29 14:54:49 +01:00
|
|
|
: interruptEventNotifier(interruptEventNotifier)
|
|
|
|
|
{
|
|
|
|
|
this->accept(serverSocketFileDescriptor);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
::fcntl(
|
2022-03-29 14:54:49 +01:00
|
|
|
this->socketFileDescriptor.value(),
|
2022-02-05 15:32:08 +00:00
|
|
|
F_SETFL,
|
2022-03-29 14:54:49 +01:00
|
|
|
::fcntl(this->socketFileDescriptor.value(), F_GETFL, 0) | O_NONBLOCK
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
this->epollInstance.addEntry(
|
|
|
|
|
this->socketFileDescriptor.value(),
|
2022-09-26 21:21:57 +01:00
|
|
|
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
2022-03-29 14:54:49 +01:00
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
this->enableReadInterrupts();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
Connection::~Connection() {
|
|
|
|
|
this->close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Connection::getIpAddress() const {
|
2024-07-23 21:14:22 +01:00
|
|
|
auto ipAddress = std::array<char, INET_ADDRSTRLEN>{};
|
2022-03-29 14:54:49 +01:00
|
|
|
|
|
|
|
|
if (::inet_ntop(AF_INET, &(socketAddress.sin_addr), ipAddress.data(), INET_ADDRSTRLEN) == nullptr) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Failed to convert client IP address to text form."};
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2022-03-29 14:54:49 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return {ipAddress.data()};
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-01 21:01:37 +01:00
|
|
|
std::vector<RawPacket> Connection::readRawPackets() {
|
2024-07-23 21:14:22 +01:00
|
|
|
auto output = std::vector<RawPacket>{};
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
do {
|
|
|
|
|
const auto bytes = this->read();
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
auto bufferSize = bytes.size();
|
|
|
|
|
for (auto byteIndex = std::size_t{0}; byteIndex < bufferSize; byteIndex++) {
|
2022-11-18 20:26:20 +00:00
|
|
|
auto byte = bytes[byteIndex];
|
|
|
|
|
|
|
|
|
|
if (byte == 0x03) {
|
|
|
|
|
/*
|
|
|
|
|
* This is an interrupt packet - it doesn't carry any of the usual packet frame bytes, so we'll
|
|
|
|
|
* just add them here, in order to keep things consistent.
|
|
|
|
|
*
|
|
|
|
|
* Because we're effectively faking the packet frame, we can use any value for the checksum.
|
|
|
|
|
*/
|
|
|
|
|
output.push_back({'$', byte, '#', 'F', 'F'});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
if (byte == '$') {
|
|
|
|
|
// Beginning of packet
|
|
|
|
|
RawPacket rawPacket;
|
|
|
|
|
rawPacket.push_back('$');
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
auto packetIndex = byteIndex;
|
|
|
|
|
bool validPacket = false;
|
|
|
|
|
bool isByteEscaped = false;
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
for (packetIndex++; packetIndex < bufferSize; packetIndex++) {
|
|
|
|
|
byte = bytes[packetIndex];
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
if (byte == '}' && !isByteEscaped) {
|
|
|
|
|
isByteEscaped = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
if (!isByteEscaped) {
|
|
|
|
|
if (byte == '$') {
|
|
|
|
|
// Unexpected end of packet
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
if (byte == '#') {
|
|
|
|
|
// End of packet data
|
|
|
|
|
if ((bufferSize - 1) < (packetIndex + 2)) {
|
|
|
|
|
// There should be at least two more bytes in the buffer, for the checksum.
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
rawPacket.push_back(byte);
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
// Add the checksum bytes and break the loop
|
|
|
|
|
rawPacket.push_back(bytes[++packetIndex]);
|
|
|
|
|
rawPacket.push_back(bytes[++packetIndex]);
|
|
|
|
|
validPacket = true;
|
2022-03-27 19:43:20 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
} else {
|
|
|
|
|
// Escaped bytes are XOR'd with a 0x20 mask.
|
|
|
|
|
byte ^= 0x20;
|
|
|
|
|
isByteEscaped = false;
|
2022-03-27 19:43:20 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-18 20:26:20 +00:00
|
|
|
rawPacket.push_back(byte);
|
2022-03-27 19:43:20 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-18 20:49:17 +00:00
|
|
|
if (!validPacket) {
|
|
|
|
|
Logger::warning("GDB client sent invalid packet data - ignoring");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2023-05-07 16:45:04 +01:00
|
|
|
Logger::debug(
|
|
|
|
|
"Read GDB packet: "
|
|
|
|
|
+ Services::StringService::replaceUnprintable(
|
2024-07-23 21:14:22 +01:00
|
|
|
std::string{rawPacket.begin(), rawPacket.end()}
|
2023-05-07 16:45:04 +01:00
|
|
|
)
|
|
|
|
|
);
|
2022-04-08 22:17:46 +01:00
|
|
|
|
2024-10-19 23:10:34 +01:00
|
|
|
if (this->packetAcknowledgement) {
|
|
|
|
|
// Acknowledge receipt
|
|
|
|
|
this->write({'+'});
|
|
|
|
|
}
|
2022-11-18 20:49:17 +00:00
|
|
|
|
|
|
|
|
output.emplace_back(std::move(rawPacket));
|
|
|
|
|
byteIndex = packetIndex;
|
2022-03-27 19:43:20 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2022-11-18 20:26:20 +00:00
|
|
|
|
|
|
|
|
} while (output.empty());
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
return output;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Connection::writePacket(const ResponsePacket& packet) {
|
2022-04-08 22:17:46 +01:00
|
|
|
const auto rawPacket = packet.toRawPacket();
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
Logger::debug("Writing GDB packet: " + std::string{rawPacket.begin(), rawPacket.end()});
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-10-19 23:10:34 +01:00
|
|
|
this->write(rawPacket);
|
|
|
|
|
|
|
|
|
|
if (this->packetAcknowledgement) {
|
|
|
|
|
auto attempts = std::size_t{0};
|
|
|
|
|
auto ackByte = this->readSingleByte(false);
|
|
|
|
|
while (ackByte != '+') {
|
|
|
|
|
if (attempts > 10) {
|
|
|
|
|
throw ClientCommunicationError{
|
|
|
|
|
"Failed to write GDB response packet - client failed to acknowledge receipt - retry limit reached"
|
|
|
|
|
};
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-10-19 23:10:34 +01:00
|
|
|
if (ackByte == '-') {
|
|
|
|
|
// GDB has requested retransmission
|
|
|
|
|
Logger::debug("Sending packet again, upon GDB's request");
|
|
|
|
|
this->write(rawPacket);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ackByte = this->readSingleByte(false);
|
|
|
|
|
++attempts;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
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) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Failed to accept GDB Remote Serial Protocol connection"};
|
2022-03-29 14:54:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->socketFileDescriptor = socketFileDescriptor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Connection::close() noexcept {
|
|
|
|
|
if (this->socketFileDescriptor.value_or(-1) >= 0) {
|
|
|
|
|
::close(this->socketFileDescriptor.value());
|
|
|
|
|
this->socketFileDescriptor = std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 01:04:14 +01:00
|
|
|
std::vector<unsigned char> Connection::read(
|
2022-11-16 23:50:28 +00:00
|
|
|
std::optional<std::size_t> bytes,
|
2022-03-28 01:04:14 +01:00
|
|
|
bool interruptible,
|
|
|
|
|
std::optional<std::chrono::milliseconds> timeout
|
|
|
|
|
) {
|
2024-11-28 21:49:03 +00:00
|
|
|
if (bytes.has_value() && *bytes > Connection::ABSOLUTE_MAXIMUM_PACKET_READ_SIZE) {
|
|
|
|
|
throw InternalFatalErrorException{"Attempted to read too many bytes from GDB socket"};
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-19 23:11:22 +01:00
|
|
|
auto output = std::vector<unsigned char>{};
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-16 21:23:03 +01:00
|
|
|
if (this->readInterruptEnabled != interruptible) {
|
|
|
|
|
if (interruptible) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->enableReadInterrupts();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} else {
|
2022-04-16 21:23:03 +01:00
|
|
|
this->disableReadInterrupts();
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-16 21:23:03 +01:00
|
|
|
// Clear any previous interrupts that are still hanging around
|
|
|
|
|
this->interruptEventNotifier.clear();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-03-28 01:04:14 +01:00
|
|
|
const auto eventFileDescriptor = this->epollInstance.waitForEvent(timeout);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-16 21:20:13 +01:00
|
|
|
if (!eventFileDescriptor.has_value()) {
|
|
|
|
|
// Timed out
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eventFileDescriptor.value() == this->interruptEventNotifier.getFileDescriptor()) {
|
2022-03-28 01:04:14 +01:00
|
|
|
// Interrupted
|
|
|
|
|
this->interruptEventNotifier.clear();
|
2024-07-23 21:14:22 +01:00
|
|
|
throw DebugServerInterrupted{};
|
2022-03-28 01:04:14 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-11-17 21:00:45 +00:00
|
|
|
const auto bytesToRead = bytes.value_or(Connection::ABSOLUTE_MAXIMUM_PACKET_READ_SIZE);
|
|
|
|
|
output.resize(bytesToRead, 0x00);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-11-17 21:00:45 +00:00
|
|
|
const auto bytesRead = ::read(
|
|
|
|
|
this->socketFileDescriptor.value(),
|
|
|
|
|
output.data(),
|
|
|
|
|
bytesToRead
|
|
|
|
|
);
|
2022-11-16 23:50:28 +00:00
|
|
|
|
2022-11-17 21:00:45 +00:00
|
|
|
if (bytesRead < 0) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw ClientCommunicationError{
|
2022-11-17 21:00:45 +00:00
|
|
|
"Failed to read data from GDB client - error code: " + std::to_string(errno)
|
2024-07-23 21:14:22 +01:00
|
|
|
};
|
2022-03-28 01:04:14 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-11-17 21:00:45 +00:00
|
|
|
if (bytesRead == 0) {
|
|
|
|
|
// Client has disconnected
|
2024-07-23 21:14:22 +01:00
|
|
|
throw ClientDisconnected{};
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-17 21:00:45 +00:00
|
|
|
if (bytesRead != output.size()) {
|
|
|
|
|
output.resize(static_cast<unsigned long>(std::max(ssize_t{0}, bytesRead)));
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return output;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
std::optional<unsigned char> Connection::readSingleByte(bool interruptible) {
|
2024-07-23 21:14:22 +01:00
|
|
|
auto bytes = this->read(1, interruptible, std::chrono::milliseconds{300});
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!bytes.empty()) {
|
|
|
|
|
return bytes.front();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return std::nullopt;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Connection::write(const std::vector<unsigned char>& buffer) {
|
2022-03-29 14:54:49 +01:00
|
|
|
if (::write(this->socketFileDescriptor.value(), buffer.data(), buffer.size()) == -1) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (errno == EPIPE || errno == ECONNRESET) {
|
|
|
|
|
// Connection was closed
|
2024-07-23 21:14:22 +01:00
|
|
|
throw ClientDisconnected{};
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
throw ClientCommunicationError{
|
2022-11-17 21:00:45 +00:00
|
|
|
"Failed to write " + std::to_string(buffer.size()) + " bytes to GDP client socket - error no: "
|
|
|
|
|
+ std::to_string(errno)
|
2024-07-23 21:14:22 +01:00
|
|
|
};
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Connection::disableReadInterrupts() {
|
2022-03-28 01:04:14 +01:00
|
|
|
this->epollInstance.removeEntry(this->interruptEventNotifier.getFileDescriptor());
|
2022-02-05 15:32:08 +00:00
|
|
|
this->readInterruptEnabled = false;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Connection::enableReadInterrupts() {
|
2022-03-28 01:04:14 +01:00
|
|
|
this->epollInstance.addEntry(
|
|
|
|
|
this->interruptEventNotifier.getFileDescriptor(),
|
2022-09-26 21:21:57 +01:00
|
|
|
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
2022-03-28 01:04:14 +01:00
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->readInterruptEnabled = true;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|