Skip to content
Commits on Source (3)
Subproject commit 8a0ea2d0e699863df5fe1c91caf2d7b0855957be Subproject commit a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1
#pragma once #pragma once
#include <Base_Receiver.h> #include <Base_Receiver.h>
#include <Base_Configurator.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 { namespace inaf::oasbo::Receivers {
class UDPProtocol: public BaseReceiver { class UDPProtocol: public BaseReceiver {
protected: 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(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: public:
/**
* @brief Destroys the UDPProtocol object.
*/
~UDPProtocol(); ~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; 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 setHost(std::string host) override;
void setIp(std::string); /**
std::string getIp(){return this->ip;} * @brief Sets the IP address to bind the UDP socket to.
void setPort(int); *
int getPort(){return this->port;} * @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; int connectToClient() override;
/**
* @brief Closes the connection to the client.
*
* @return 0 if the connection is closed successfully, -1 otherwise.
*/
int closeConnectionToClient() override; 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; 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; friend class UDPProtocolBuilder;
}; };
class UDPProtocolBuilder { class UDPProtocolBuilder {
protected: protected:
UDPProtocol *protocol; UDPProtocol *protocol; /**< The UDPProtocol object being built. */
public: 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" }; * @brief Constructs a UDPProtocolBuilder object.
std::string port_key { "port" }; */
UDPProtocolBuilder(); 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); UDPProtocolBuilder(std::string ip, int port);
/**
* @brief Destroys the UDPProtocolBuilder object.
*/
~UDPProtocolBuilder(); ~UDPProtocolBuilder();
/**
* @brief Resets the UDPProtocolBuilder object.
*/
void reset(); 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); 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); 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); UDPProtocolBuilder* setPort(int port);
/**
* @brief Gets the UDPProtocol object that has been built.
*
* @return A pointer to the UDPProtocol object.
*/
UDPProtocol* getReceiver(); UDPProtocol* getReceiver();
}; };
} }
...@@ -33,12 +33,12 @@ UDPProtocol::~UDPProtocol() { ...@@ -33,12 +33,12 @@ UDPProtocol::~UDPProtocol() {
closeConnectionToClient(); closeConnectionToClient();
} }
int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize, int UDPProtocol::receiveAtLeastNbytes(uint8_t *buff, int n_bytes,
int packetSize) { int max_size) {
int bytercv = 0; int bytercv = 0;
socklen_t len = sizeof(cliaddr); socklen_t len = sizeof(cliaddr);
while (bytercv < headerSize) { while (bytercv < n_bytes && this->checkIncomingPackets) {
int rcv = recvfrom(srv_sock, &buff[bytercv], packetSize + 1, // +1 to recognized if there are more bytes than expected 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); 0, (struct sockaddr*) &cliaddr, &len);
bytercv += rcv; bytercv += rcv;
...@@ -46,23 +46,26 @@ int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize, ...@@ -46,23 +46,26 @@ int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize,
return -1; return -1;
} }
} }
if (!this->checkIncomingPackets) { // interrupted by closeConnectionToClient before receiving all the N bytes.
return -1;
}
return bytercv; return bytercv;
} }
int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) { int UDPProtocol::receiveFromClient(Packets::BasePacket &pack) {
bool headerFlag = false; bool headerFlag = false; // tells if the header has been received
uint headerSize = pack.getHeaderSize(); uint headerSize = pack.getHeaderSize();
uint packSize = pack.getPacketStructureByteSize(); uint packSize = pack.getPacketStructureByteSize();
uint tailSize = pack.getTailSize(); uint tailSize = pack.getTailSize();
uint payloadSize = 0; uint payloadSize = 0;
uint totPacketSize = 0; uint totPacketSize = 0;
ssize_t to_be_received = 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; int tot_byte_rcv = 0;
while (true) { while (this->checkIncomingPackets) {
while (!headerFlag) { // until the header has not received 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. int rcv = receiveAtLeastNbytes(buff, headerSize, packSize); // receive at least headerSize byte, maximum packSize for each udp rcv.
if (rcv == -1) { if (rcv < 0) {
delete[] buff; delete[] buff;
return -1; return -1;
} }
...@@ -79,25 +82,30 @@ int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) { ...@@ -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 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. if (to_be_received == 0) { // whole packet has been received, we can return.
pack.copyToMemory(&buff[headerSize], pack.copyToMemory(&buff[headerSize], tot_byte_rcv - headerSize,
tot_byte_rcv - headerSize, headerSize); // copy the buffer into packet except already copied header headerSize); // copy the buffer into packet except already copied header
delete[] buff; delete[] buff;
return tot_byte_rcv; 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); resetPacket(pack, tot_byte_rcv);
delete[] buff; delete[] buff;
return -1; 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) { if (rcv == -1) {
delete[] buff; delete[] buff;
delete[] tmp_buff; delete[] tmp_buff;
resetPacket(pack, tot_byte_rcv); resetPacket(pack, tot_byte_rcv);
return -1; 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::vector<uint8_t> vec;
std::copy(tmp_buff, tmp_buff + headerSize, std::back_inserter(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. if (pack.isRecognizedHeader(vec)) { //another header received, save it and discard previous data.
...@@ -116,6 +124,7 @@ int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) { ...@@ -116,6 +124,7 @@ int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
} }
delete[] tmp_buff; delete[] tmp_buff;
} }
return -1; // connection interrupted by closeConnectionToClient
} }
int UDPProtocol::connectToClient() { int UDPProtocol::connectToClient() {
...@@ -136,7 +145,8 @@ int UDPProtocol::connectToClient() { ...@@ -136,7 +145,8 @@ int UDPProtocol::connectToClient() {
sizeof tv) < 0) { sizeof tv) < 0) {
time_t now = time(nullptr); time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") 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; return -1;
} }
...@@ -154,6 +164,7 @@ int UDPProtocol::connectToClient() { ...@@ -154,6 +164,7 @@ int UDPProtocol::connectToClient() {
} }
int UDPProtocol::closeConnectionToClient() { int UDPProtocol::closeConnectionToClient() {
checkIncomingPackets = false;
if (srv_sock != -1) { if (srv_sock != -1) {
::close(srv_sock); ::close(srv_sock);
srv_sock = -1; srv_sock = -1;
...@@ -165,7 +176,7 @@ bool UDPProtocol::isConnectedToClient() const { ...@@ -165,7 +176,7 @@ bool UDPProtocol::isConnectedToClient() const {
return srv_sock != -1; 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]; uint8_t *buff = new uint8_t[bytes];
std::memset(buff, 0, bytes); std::memset(buff, 0, bytes);
int toBeReset = std::min( int toBeReset = std::min(
......