2021-04-04 21:04:12 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netinet/in.h>
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <cstdint>
|
2021-06-22 23:52:31 +01:00
|
|
|
#include <utility>
|
2022-10-09 13:10:17 +01:00
|
|
|
#include <optional>
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <vector>
|
|
|
|
|
#include <queue>
|
|
|
|
|
#include <array>
|
2022-03-28 01:04:14 +01:00
|
|
|
#include <chrono>
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-15 22:05:50 +01:00
|
|
|
#include "src/Helpers/EventFdNotifier.hpp"
|
2022-03-28 01:04:14 +01:00
|
|
|
#include "src/Helpers/EpollInstance.hpp"
|
2022-03-27 19:43:20 +01:00
|
|
|
|
2024-10-19 23:11:22 +01:00
|
|
|
#include "Packet.hpp"
|
|
|
|
|
#include "ResponsePackets/ResponsePacket.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
namespace DebugServer::Gdb
|
2021-04-04 21:04:12 +01:00
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The Connection class represents an active connection between the GDB RSP server and client.
|
|
|
|
|
*/
|
|
|
|
|
class Connection
|
|
|
|
|
{
|
|
|
|
|
public:
|
2022-11-16 23:50:28 +00:00
|
|
|
/*
|
|
|
|
|
* GDB should never attempt to send more than this in a single instance.
|
|
|
|
|
*
|
|
|
|
|
* In the event that it does, we assume the worst and kill the connection.
|
|
|
|
|
*/
|
2022-12-13 21:10:40 +00:00
|
|
|
static constexpr auto ABSOLUTE_MAXIMUM_PACKET_READ_SIZE = 2097000; // 2MiB
|
2022-11-16 23:50:28 +00:00
|
|
|
|
2024-10-19 23:10:34 +01:00
|
|
|
bool packetAcknowledgement = true;
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-03-28 01:04:14 +01:00
|
|
|
Connection() = delete;
|
|
|
|
|
Connection(const Connection&) = delete;
|
2022-03-29 14:54:49 +01:00
|
|
|
Connection& operator = (Connection&) = delete;
|
2022-03-29 14:54:55 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: Implement this. For now, use the move constructor.
|
|
|
|
|
*/
|
2022-03-29 14:54:49 +01:00
|
|
|
Connection& operator = (Connection&&) = delete;
|
|
|
|
|
|
2022-03-28 01:04:14 +01:00
|
|
|
Connection(Connection&& other) noexcept
|
2023-08-19 21:53:00 +01:00
|
|
|
: socketFileDescriptor(other.socketFileDescriptor)
|
|
|
|
|
, interruptEventNotifier(other.interruptEventNotifier)
|
2022-03-28 01:04:14 +01:00
|
|
|
, epollInstance(std::move(other.epollInstance))
|
|
|
|
|
, readInterruptEnabled(other.readInterruptEnabled)
|
|
|
|
|
{
|
2022-03-29 14:54:49 +01:00
|
|
|
other.socketFileDescriptor = std::nullopt;
|
|
|
|
|
}
|
2022-03-28 01:04:14 +01:00
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
~Connection();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Obtains the human readable IP address of the connected client.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2022-03-29 14:54:49 +01:00
|
|
|
[[nodiscard]] std::string getIpAddress() const;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
2022-03-27 19:43:20 +01:00
|
|
|
* Waits for incoming data from the client and returns the raw GDB packets.
|
2021-04-04 21:04:12 +01:00
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2022-10-01 21:01:37 +01:00
|
|
|
std::vector<RawPacket> readRawPackets();
|
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-10-06 21:12:31 +01:00
|
|
|
private:
|
2022-03-29 14:54:49 +01:00
|
|
|
std::optional<int> socketFileDescriptor;
|
2022-03-28 01:04:14 +01:00
|
|
|
|
2021-10-06 21:12:31 +01:00
|
|
|
struct sockaddr_in socketAddress = {};
|
|
|
|
|
|
|
|
|
|
/**
|
2022-04-15 22:05:50 +01:00
|
|
|
* The interruptEventNotifier (instance of EventFdNotifier) allows us to interrupt blocking I/O calls on this
|
|
|
|
|
* connection's socket. Under the hood, the EventFdNotifier class is just an RAII wrapper for a Linux eventfd
|
2022-03-29 14:54:55 +01:00
|
|
|
* object.
|
|
|
|
|
*
|
|
|
|
|
* The file descriptors of the eventfd object and the socket are both added to an EpollInstance (which is just
|
|
|
|
|
* an RAII wrapper for a Linux epoll instance). The EpollInstance object is then used to wait for events on
|
|
|
|
|
* either of the two file descriptors. See any of the Connection I/O functions (e.g Connection::read()) for
|
|
|
|
|
* more on this.
|
|
|
|
|
*
|
2022-04-15 22:05:50 +01:00
|
|
|
* See the EventFdNotifier and EpollInstance classes for more.
|
2021-10-06 21:12:31 +01:00
|
|
|
*/
|
2022-04-15 22:05:50 +01:00
|
|
|
EventFdNotifier& interruptEventNotifier;
|
2022-03-29 14:54:55 +01:00
|
|
|
EpollInstance epollInstance = EpollInstance();
|
|
|
|
|
|
2021-10-06 21:12:31 +01:00
|
|
|
bool readInterruptEnabled = false;
|
|
|
|
|
|
2022-03-29 14:54:49 +01:00
|
|
|
/**
|
|
|
|
|
* Accepts a connection on serverSocketFileDescriptor.
|
|
|
|
|
*
|
|
|
|
|
* @param serverSocketFileDescriptor
|
|
|
|
|
*/
|
|
|
|
|
void accept(int serverSocketFileDescriptor);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Closes the connection with the client.
|
|
|
|
|
*/
|
|
|
|
|
void close() noexcept;
|
|
|
|
|
|
2021-10-06 21:12:31 +01:00
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
* the read (via means of this->interruptEventNotifier). This flag has no effect if this->readInterruptEnabled
|
|
|
|
|
* is false.
|
|
|
|
|
*
|
2022-03-28 01:04:14 +01:00
|
|
|
* @param timeout
|
2021-10-06 21:12:31 +01:00
|
|
|
* The timeout in milliseconds. If not supplied, no timeout will be applied.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2022-03-27 18:34:08 +01:00
|
|
|
std::vector<unsigned char> read(
|
2022-11-16 23:50:28 +00:00
|
|
|
std::optional<std::size_t> bytes = std::nullopt,
|
2022-03-27 18:34:08 +01:00
|
|
|
bool interruptible = true,
|
2022-03-28 01:04:14 +01:00
|
|
|
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
2022-03-27 18:34:08 +01:00
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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);
|
|
|
|
|
|
2022-03-29 14:54:55 +01:00
|
|
|
/**
|
|
|
|
|
* Removes this->interruptEventNotifier's file descriptor from the EpollInstance (this->epollInstance),
|
|
|
|
|
* preventing subsequent I/O operations on this->socketFileDescriptor from being interrupted.
|
|
|
|
|
*/
|
2021-10-06 21:12:31 +01:00
|
|
|
void disableReadInterrupts();
|
|
|
|
|
|
2022-03-29 14:54:55 +01:00
|
|
|
/**
|
|
|
|
|
* Inserts this->interruptEventNotifier's file descriptor into the EpollInstance (this->epollInstance),
|
|
|
|
|
* allowing for subsequent I/O operations on this->socketFileDescriptor to be interrupted.
|
|
|
|
|
*/
|
2021-10-06 21:12:31 +01:00
|
|
|
void enableReadInterrupts();
|
2021-04-04 21:04:12 +01:00
|
|
|
};
|
|
|
|
|
}
|