Skip to content
Commits on Source (3)
Subproject commit 8a0ea2d0e699863df5fe1c91caf2d7b0855957be
Subproject commit a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1
#pragma once
#include <Base_Receiver.h>
#include <Base_Configurator.h>
/**
* @brief The UDPProtocol class is a derived class of BaseReceiver and represents a UDP protocol receiver.
* check the Base_Receiver.h file for more information.
*/
namespace inaf::oasbo::Receivers {
class UDPProtocol: public BaseReceiver {
protected:
/**
* @brief Constructs a UDPProtocol object with the specified IP and port.
*
* @param ip The IP address to bind the UDP socket to.
* @param prt The port number to bind the UDP socket to.
*/
UDPProtocol(std::string ip, int prt);
UDPProtocol();
int srv_sock;
std::string ip { };
int port;
struct sockaddr_in cliaddr;
struct sockaddr_in srvaddr;
bool split_ip_port(const std::string &ip_port, std::string &ip,
int &port);
int receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize,
int packetSize);
void resetPacket(PacketLib::BasePacket&, int bytes);
/**
* @brief Constructs a UDPProtocol object with default IP and port.
*/
UDPProtocol();
int srv_sock; /**< The server socket descriptor. */
std::string ip { }; /**< The IP address to bind the UDP socket to. */
int port; /**< The port number to bind the UDP socket to. */
struct sockaddr_in cliaddr; /**< The client address structure. */
struct sockaddr_in srvaddr; /**< The server address structure. */
bool checkIncomingPackets = true; /**< Flag that tells if it has to check for incoming udp packets. Set to false when calling closeConnectionToClient.
* Used to avoid the infinite loop in receiveAtLeastNbytes.
*/
/**
* @brief Splits the IP and port from the given IP:port string.
*
* @param ip_port The IP:port string to split.
* @param ip The extracted IP address.
* @param port The extracted port number.
* @return true if the IP and port were successfully extracted, false otherwise.
*/
bool split_ip_port(const std::string &ip_port, std::string &ip, int &port);
/**
* @brief Receives at least the specified number of bytes from the client.
* Helper function to receive at least the header of the packet.
* @param buff The buffer to store the received data.
* @param n_bytes The number of bytes to receive.
* @param max_size The max size of bytes to receive.
* @return The number of bytes received.
*/
int receiveAtLeastNbytes(uint8_t *buff, int n_bytes, int max_size);
/**
* @brief Resets the packet object and sets the number of bytes received.
*
* @param packet The packet object to reset.
* @param bytes The number of bytes received.
*/
void resetPacket(Packets::BasePacket &packet, int bytes);
public:
/**
* @brief Destroys the UDPProtocol object.
*/
~UDPProtocol();
/**
* @brief Gets the host name or IP address that the UDP socket is bound to.
*
* @return The host name or IP address.
*/
std::string getHost() override;
/**
* @brief Sets the host name or IP address to bind the UDP socket to.
*
* @param host The host name or IP address.
*/
void setHost(std::string host) override;
void setIp(std::string);
std::string getIp(){return this->ip;}
void setPort(int);
int getPort(){return this->port;}
/**
* @brief Sets the IP address to bind the UDP socket to.
*
* @param ip The IP address.
*/
void setIp(std::string ip);
/**
* @brief Gets the IP address that the UDP socket is bound to.
*
* @return The IP address.
*/
std::string getIp() {
return this->ip;
}
/**
* @brief Sets the port number to bind the UDP socket to.
*
* @param port The port number.
*/
void setPort(int port);
/**
* @brief Gets the port number that the UDP socket is bound to.
*
* @return The port number.
*/
int getPort() {
return this->port;
}
/**
* @brief Connects to the client.
*
* @return 0 if the connection is successful, -1 otherwise.
*/
int connectToClient() override;
/**
* @brief Closes the connection to the client.
*
* @return 0 if the connection is closed successfully, -1 otherwise.
*/
int closeConnectionToClient() override;
/**
* @brief Checks if the UDP socket is connected to the client.
*
* @return true if the UDP socket is connected to the client, false otherwise.
*/
bool isConnectedToClient() const override;
int receiveFromClient(PacketLib::BasePacket&) override;
/**
* @brief Receives a packet from the client.
*
* @param packet The packet object to store the received data.
* @return The number of bytes received.
*/
int receiveFromClient(Packets::BasePacket &packet) override;
friend class UDPProtocolBuilder;
};
class UDPProtocolBuilder {
protected:
UDPProtocol *protocol;
UDPProtocol *protocol; /**< The UDPProtocol object being built. */
public:
std::string config_target { "udpreceiver" }; /**< The configuration target. */
std::string ip_key { "ip" }; /**< The configuration key for IP address. */
std::string port_key { "port" }; /**< The configuration key for port number. */
std::string config_target {"udpreceiver"};
std::string ip_key { "ip" };
std::string port_key { "port" };
/**
* @brief Constructs a UDPProtocolBuilder object.
*/
UDPProtocolBuilder();
/**
* @brief Constructs a UDPProtocolBuilder object with the specified IP and port.
*
* @param ip The IP address to bind the UDP socket to.
* @param port The port number to bind the UDP socket to.
*/
UDPProtocolBuilder(std::string ip, int port);
/**
* @brief Destroys the UDPProtocolBuilder object.
*/
~UDPProtocolBuilder();
/**
* @brief Resets the UDPProtocolBuilder object.
*/
void reset();
/**
* @brief Configures the UDPProtocolBuilder object from a configurator.
*
* @param conf The configurator object.
* @return A pointer to the UDPProtocolBuilder object.
*/
UDPProtocolBuilder* configFrom(Configurators::BaseConfigurator &conf);
/**
* @brief Sets the IP address to bind the UDP socket to.
*
* @param ip The IP address.
* @return A pointer to the UDPProtocolBuilder object.
*/
UDPProtocolBuilder* setIp(std::string ip);
/**
* @brief Sets the port number to bind the UDP socket to.
*
* @param port The port number.
* @return A pointer to the UDPProtocolBuilder object.
*/
UDPProtocolBuilder* setPort(int port);
/**
* @brief Gets the UDPProtocol object that has been built.
*
* @return A pointer to the UDPProtocol object.
*/
UDPProtocol* getReceiver();
};
}
......@@ -33,12 +33,12 @@ UDPProtocol::~UDPProtocol() {
closeConnectionToClient();
}
int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize,
int packetSize) {
int UDPProtocol::receiveAtLeastNbytes(uint8_t *buff, int n_bytes,
int max_size) {
int bytercv = 0;
socklen_t len = sizeof(cliaddr);
while (bytercv < headerSize) {
int rcv = recvfrom(srv_sock, &buff[bytercv], packetSize + 1, // +1 to recognized if there are more bytes than expected
while (bytercv < n_bytes && this->checkIncomingPackets) {
int rcv = recvfrom(srv_sock, &buff[bytercv], max_size + 1, // +1 to recognized if there are more bytes than expected
0, (struct sockaddr*) &cliaddr, &len);
bytercv += rcv;
......@@ -46,23 +46,26 @@ int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize,
return -1;
}
}
if (!this->checkIncomingPackets) { // interrupted by closeConnectionToClient before receiving all the N bytes.
return -1;
}
return bytercv;
}
int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
bool headerFlag = false;
int UDPProtocol::receiveFromClient(Packets::BasePacket &pack) {
bool headerFlag = false; // tells if the header has been received
uint headerSize = pack.getHeaderSize();
uint packSize = pack.getPacketStructureByteSize();
uint tailSize = pack.getTailSize();
uint payloadSize = 0;
uint totPacketSize = 0;
ssize_t to_be_received = 0;
uint8_t *buff = new uint8_t[(packSize + headerSize) * headerSize]; // to avoid overflow
uint8_t *buff = new uint8_t[(packSize + headerSize) * headerSize]; // * headerSize to avoid overflow
int tot_byte_rcv = 0;
while (true) {
while (this->checkIncomingPackets) {
while (!headerFlag) { // until the header has not received
int rcv = receiveAtLeastHeaderSizeBytes(buff, headerSize, packSize); // receive at least headerSize byte, maximum packSize for each udp rcv.
if (rcv == -1) {
int rcv = receiveAtLeastNbytes(buff, headerSize, packSize); // receive at least headerSize byte, maximum packSize for each udp rcv.
if (rcv < 0) {
delete[] buff;
return -1;
}
......@@ -79,25 +82,30 @@ int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
to_be_received = totPacketSize - tot_byte_rcv; // Calculate how much is still left to read
}
if (to_be_received == 0) { // whole packet has been received.
pack.copyToMemory(&buff[headerSize],
tot_byte_rcv - headerSize, headerSize); // copy the buffer into packet except already copied header
if (to_be_received == 0) { // whole packet has been received, we can return.
pack.copyToMemory(&buff[headerSize], tot_byte_rcv - headerSize,
headerSize); // copy the buffer into packet except already copied header
delete[] buff;
return tot_byte_rcv;
}
if (to_be_received < 0) { // error,received more bytes then expected.
if (to_be_received < 0) {// error,received more bytes then expected, we can return.
resetPacket(pack, tot_byte_rcv);
delete[] buff;
return -1;
}
uint8_t *tmp_buff = new uint8_t[packSize + headerSize]; // maximum receivable in receiveAtLeastHeaderSizeBytes
int rcv = receiveAtLeastHeaderSizeBytes(tmp_buff, headerSize, packSize);
// go ahead until the rest of the packet received or connection terminates or another header is received.
uint8_t *tmp_buff = new uint8_t[packSize + headerSize]; // maximum receivable in receiveAtLeastNBytes
int rcv = receiveAtLeastNbytes(tmp_buff, headerSize, packSize);
if (rcv == -1) {
delete[] buff;
delete[] tmp_buff;
resetPacket(pack, tot_byte_rcv);
return -1;
}
// copy the content of the buffer into a vector to check if it is a header. If it is,
// save it and discard previous data, otherwise append to current buff.
std::vector<uint8_t> vec;
std::copy(tmp_buff, tmp_buff + headerSize, std::back_inserter(vec));
if (pack.isRecognizedHeader(vec)) { //another header received, save it and discard previous data.
......@@ -116,6 +124,7 @@ int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
}
delete[] tmp_buff;
}
return -1; // connection interrupted by closeConnectionToClient
}
int UDPProtocol::connectToClient() {
......@@ -136,7 +145,8 @@ int UDPProtocol::connectToClient() {
sizeof tv) < 0) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[UDP Receiver]\t" << "Error setting timeout to socket" << std::endl;
<< "]\t[UDP Receiver]\t" << "Error setting timeout to socket"
<< std::endl;
return -1;
}
......@@ -154,6 +164,7 @@ int UDPProtocol::connectToClient() {
}
int UDPProtocol::closeConnectionToClient() {
checkIncomingPackets = false;
if (srv_sock != -1) {
::close(srv_sock);
srv_sock = -1;
......@@ -165,7 +176,7 @@ bool UDPProtocol::isConnectedToClient() const {
return srv_sock != -1;
}
void UDPProtocol::resetPacket(PacketLib::BasePacket &pack, int bytes) {
void UDPProtocol::resetPacket(Packets::BasePacket &pack, int bytes) {
uint8_t *buff = new uint8_t[bytes];
std::memset(buff, 0, bytes);
int toBeReset = std::min(
......