2021-04-04 21:04:12 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
2021-06-22 23:52:31 +01:00
|
|
|
#include <utility>
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <vector>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <queue>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
|
|
#include "src/Helpers/EventNotifier.hpp"
|
|
|
|
|
#include "src/DebugServers/GdbRsp/CommandPackets/CommandPacket.hpp"
|
|
|
|
|
#include "src/DebugServers/GdbRsp/ResponsePackets/ResponsePacket.hpp"
|
|
|
|
|
|
|
|
|
|
namespace Bloom::DebugServers::Gdb
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The Connection class represents an active connection between the GDB RSP server and client.
|
|
|
|
|
*
|
|
|
|
|
* All interfacing with the GDB client should take place here.
|
|
|
|
|
*/
|
|
|
|
|
class Connection
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
int socketFileDescriptor = -1;
|
|
|
|
|
int eventFileDescriptor = -1;
|
|
|
|
|
|
|
|
|
|
struct sockaddr_in socketAddress = {};
|
|
|
|
|
int maxPacketSize = 1024;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The interruptEventNotifier allows us to interrupt blocking IO calls on the GDB debug server.
|
|
|
|
|
* Under the hood, this is just a wrapper for a Linux event notifier. See the EventNotifier class for more.
|
|
|
|
|
*/
|
|
|
|
|
std::shared_ptr<EventNotifier> interruptEventNotifier = nullptr;
|
|
|
|
|
bool readInterruptEnabled = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reads data from the client into a raw buffer.
|
|
|
|
|
*
|
|
|
|
|
* @param bytes
|
|
|
|
|
* Number of bytes to read.
|
|
|
|
|
*
|
|
|
|
|
* @param interruptible
|
|
|
|
|
* If this flag is set to false, no other component within Bloom will be able to gracefully interrupt
|
2021-05-24 20:58:49 +01:00
|
|
|
* the read (via means of this->interruptEventNotifier). This flag has no effect if this->readInterruptEnabled
|
2021-04-04 21:04:12 +01:00
|
|
|
* is false.
|
|
|
|
|
*
|
|
|
|
|
* @param msTimeout
|
|
|
|
|
* The timeout in milliseconds. If not supplied, no timeout will be applied.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
std::vector<unsigned char> read(std::size_t bytes = 0, bool interruptible = true, std::optional<int> msTimeout = std::nullopt);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Does the same as Connection::read(), but only reads a single byte.
|
|
|
|
|
*
|
|
|
|
|
* @param interruptible
|
|
|
|
|
* See Connection::read().
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
std::optional<unsigned char> readSingleByte(bool interruptible = true);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Writes data from a raw buffer to the client connection.
|
|
|
|
|
*
|
|
|
|
|
* @param buffer
|
|
|
|
|
*/
|
|
|
|
|
void write(const std::vector<unsigned char>& buffer);
|
|
|
|
|
|
|
|
|
|
void disableReadInterrupts();
|
|
|
|
|
|
|
|
|
|
void enableReadInterrupts();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* When the GDB client is waiting for the target to reach a breakpoint, this is set to true so we know when to
|
|
|
|
|
* notify the client.
|
|
|
|
|
*
|
|
|
|
|
* @TODO: This is pretty gross. Consider rethinking it.
|
|
|
|
|
*/
|
|
|
|
|
bool waitingForBreak = false;
|
|
|
|
|
|
2021-06-22 23:52:31 +01:00
|
|
|
explicit Connection(std::shared_ptr<EventNotifier> interruptEventNotifier)
|
|
|
|
|
: interruptEventNotifier(std::move(interruptEventNotifier)) {};
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
std::string getIpAddress() {
|
2021-06-22 23:52:31 +01:00
|
|
|
std::array<char, INET_ADDRSTRLEN> ipAddress = {};
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
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 any received command packets.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
std::vector<std::unique_ptr<CommandPackets::CommandPacket>> readPackets();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sends a response packet to the client.
|
|
|
|
|
*
|
|
|
|
|
* @param packet
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void writePacket(const ResponsePackets::ResponsePacket& packet);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-06-22 23:52:31 +01:00
|
|
|
[[nodiscard]] int getMaxPacketSize() const {
|
2021-04-04 21:04:12 +01:00
|
|
|
return this->maxPacketSize;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|