diff --git a/deps/Base-DAQ b/deps/Base-DAQ index 8a0ea2d0e699863df5fe1c91caf2d7b0855957be..a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1 160000 --- a/deps/Base-DAQ +++ b/deps/Base-DAQ @@ -1 +1 @@ -Subproject commit 8a0ea2d0e699863df5fe1c91caf2d7b0855957be +Subproject commit a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1 diff --git a/include/UDP_Protocol.h b/include/UDP_Protocol.h index 693f382a43fd2580c93ba9450360cdc753d80b46..567e59ea6d0ad811cae1a94b271f2704ac347f01 100755 --- a/include/UDP_Protocol.h +++ b/include/UDP_Protocol.h @@ -1,71 +1,210 @@ - #pragma once #include #include +/** + * @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(); }; - } diff --git a/src/UDP_Protocol.cpp b/src/UDP_Protocol.cpp index 2b434f68d3e59d80ebc7ddf2f23e62f9072ccfec..ed002a4181a27149faffc419629b85b4889aeef4 100755 --- a/src/UDP_Protocol.cpp +++ b/src/UDP_Protocol.cpp @@ -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 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(