#include #include #include #include #include #include #include #include #include #include using namespace inaf::oasbo::ConnectionProtocols; UDPProtocol::UDPProtocol() : UDPProtocol(std::string("127.0.0.1"), 9003) { } UDPProtocol::UDPProtocol(std::string ip, int port) : srv_sock(-1), cli_sock(-1), ip(ip), port(port) { memset(&cliaddr, 0, sizeof(cliaddr)); memset(&srvaddr, 0, sizeof(srvaddr)); // Filling server information srvaddr.sin_family = AF_INET; // IPv4 srvaddr.sin_addr.s_addr = inet_addr(ip.c_str()); srvaddr.sin_port = htons(this->port); struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; setsockopt(srv_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); } UDPProtocol::~UDPProtocol() { closeConnectionToClient(); closeConnectionToServer(); } int UDPProtocol::sendToServer(PacketLib::BasePacket &pack) { int val = ::sendto(cli_sock, pack.getBinaryPointer(), pack.getHeaderSize() + pack.getPayloadSize() + pack.getTailSize(), MSG_CONFIRM, (struct sockaddr*) &srvaddr, sizeof(srvaddr)); return val; } int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize, int packetSize) { 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 MSG_WAITFORONE, (struct sockaddr*) &cliaddr, &len); bytercv += rcv; if (rcv < 0) { return -1; } } return bytercv; } int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) { bool headerFlag = false; int headerSize = pack.getHeaderSize(); int packSize = pack.getPacketStructureByteSize(); int 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 int tot_byte_rcv = 0; while (true) { 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) { delete buff; return -1; } tot_byte_rcv += rcv; pack.copyToBinaryPointer(buff, headerSize); //copy the header into packet to be able to read it. if (!pack.isRecognizedHeader()) { // reset buffer and exit resetPacket(pack, headerSize); delete buff; return -1; } headerFlag = true; payloadSize = pack.getPayloadSize(); totPacketSize = headerSize + payloadSize + tailSize; 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.copyToBinaryPointer(&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. 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); if (rcv == -1) { delete buff; delete tmp_buff; resetPacket(pack, tot_byte_rcv); return -1; } 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. std::memset(buff, 0, tot_byte_rcv); std::memcpy(buff, tmp_buff, rcv); headerFlag = true; pack.copyToBinaryPointer(buff, headerSize); payloadSize = pack.getPayloadSize(); totPacketSize = headerSize + payloadSize + tailSize; to_be_received = totPacketSize - rcv; tot_byte_rcv = rcv; } else { // append to current buff tot_byte_rcv += rcv; std::memcpy(&buff[tot_byte_rcv - rcv], tmp_buff, rcv); to_be_received -= rcv; } delete tmp_buff; } } int UDPProtocol::connectToClient() { int sockfd; // Creating socket file descriptor if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { std::cerr << "UDP Connection: socket creation failed" << std::endl; return -1; } // Set timeout to the socket struct timeval tv; tv.tv_sec = std::numeric_limits::max(); tv.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof tv); // Bind the socket with the server address if (bind(sockfd, (const struct sockaddr*) &srvaddr, sizeof(srvaddr)) < 0) { std::cerr << "UDP Connection: bind failed" << std::endl; return -1; } this->srv_sock = sockfd; return sockfd; } int UDPProtocol::connectToServer() { int sockfd = 0; // Creating socket file descriptor if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { std::cerr << "UDP Connection: socket creation failed " << std::endl; exit(EXIT_FAILURE); } std::cout << "UDP Connection: socket creation success " << std::endl; this->cli_sock = sockfd; return sockfd; } int UDPProtocol::closeConnectionToClient() { if (srv_sock != -1) { ::close(srv_sock); srv_sock = -1; } return 1; } int UDPProtocol::closeConnectionToServer() { if (cli_sock != -1) { ::close(cli_sock); cli_sock = -1; } return 1; } bool UDPProtocol::isConnectedToClient() const { return srv_sock != -1; } bool UDPProtocol::isConnectedToServer() const { return cli_sock != -1; } void UDPProtocol::resetPacket(PacketLib::BasePacket &pack, int bytes) { uint8_t *buff = new uint8_t[bytes]; std::memset(buff, 0, bytes); int toBeReset = std::min( static_cast(pack.getPacketStructureByteSize()), bytes); pack.copyToBinaryPointer(buff, toBeReset); delete buff; } std::string UDPProtocol::getHost(){ return ip + std::to_string(port); } void UDPProtocol::setHost(std::string host){ std::string ip = {}; int port = 0; if(split_ip_port(host, ip, host)){ setIp(ip); setPort(port); } else{ std::cerr << "Connection Protocol Error: invalid IP address and port format: " << host << std::endl; } } void UDPProtocol::setIp(std::string ip ){ std::regex pattern("^(\\d{1,3}\\.){3}\\d{1,3}$"); // Check if the input string matches the expected format bool ok = true; if (!std::regex_match(ip, pattern)) { std::cerr << "Connection Protocol Error: invalid IP address: " << ip << ", setting to 127.0.0.1" << std::endl; ok = false; this->ip = std::string("127.0.0.1"); } if(ok) this->ip = ip; this->host = ip + std::to_string(port); } void UDPProtocol::setPort(int port){ if(port > 1023 && port < 65535) this->port = port; else{ std::cerr << "Connection Protocol Error: invalid port: " << port << ", setting to 9003" << std::endl; this->port = 9003; } this->host = ip + std::to_string(port); } bool UDPProtocol::split_ip_port(const std::string &ip_port, std::string &ip_address, std::string &port) { // Regex pattern to match IP address and port in the format "xxx.xxx.xxx.xxx:xxxx" std::regex pattern("^(\\d{1,3}\\.){3}\\d{1,3}:(\\d{1,5})$"); // Check if the input string matches the expected format if (!std::regex_match(ip_port, pattern)) { return false; } // Split the input string into IP address and port int colon_pos = ip_port.find(":"); ip_address = ip_port.substr(0, colon_pos); port = ip_port.substr(colon_pos + 1); return true; }