Skip to content
UDP_Protocol.cpp 5.24 KiB
Newer Older
#include <iostream>
#include <string>
#include <sys/socket.h>
Valerio Pastore's avatar
Valerio Pastore committed
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <regex>
#include <limits>
#include <algorithm>
Valerio Pastore's avatar
Valerio Pastore committed

#include <UDP_Protocol.h>

Valerio Pastore's avatar
Valerio Pastore committed
using namespace inaf::oasbo::ConnectionProtocols;
Valerio Pastore's avatar
Valerio Pastore committed

UDPProtocol::UDPProtocol() {
	this->host = std::string("127.0.0.1:9003");
	std::string port { };
	split_ip_port(host, ip, port);
	this->port = std::stoi(port);
	this->srv_sock = -1;
	this->cli_sock = -1;
Valerio Pastore's avatar
Valerio Pastore committed
	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);

}
UDPProtocol::UDPProtocol(std::string ip, int port) {
	this->host = std::string(ip).append(":").append(std::to_string(port));
	this->ip = ip;
	this->port = port;
	this->srv_sock = -1;
	this->cli_sock = -1;
	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);
}
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::receiveHeader(PacketLib::BasePacket &pack) {
	size_t bytercv = 0;
	uint8_t *buff = new uint8_t[pack.getPacketSize()];
	socklen_t len = sizeof(cliaddr);
	while (bytercv < pack.getHeaderSize()) {
		int rcv = recvfrom(srv_sock, &buff[bytercv], pack.getPacketSize(),
		MSG_WAITFORONE, (struct sockaddr*) &cliaddr, &len);
		if (rcv < 0) {
			delete buff;
			return -1;
		}else{
			bytercv+=rcv;
		}
	}
	pack.copyToBinaryPointer(buff, bytercv);
	delete buff;
	return bytercv;
}

int UDPProtocol::receivePayloadAndTail(PacketLib::BasePacket &pack, int offset) {
	int toBeReceived = pack.getHeaderSize() + pack.getPayloadSize()
			+ pack.getTailSize() - offset;
	uint8_t *buff = new uint8_t[toBeReceived];
	int bytercv = 0;
	socklen_t len = sizeof(cliaddr);
	while (bytercv < toBeReceived) {
		bytercv += recvfrom(srv_sock, &buff[bytercv], pack.getPacketSize(),
		MSG_WAITFORONE, (struct sockaddr*) &cliaddr, &len);
		if (bytercv < 0) {
			delete buff;
			resetPacket(pack, toBeReceived);
			return -1;
		}
	}
	if (bytercv != toBeReceived) {
		delete buff;
		resetPacket(pack, bytercv);
		return -1;
	} else {
		pack.copyToBinaryPointer(buff, toBeReceived);
		delete buff;
		return bytercv;
}

void UDPProtocol::resetPacket(PacketLib::BasePacket &pack, int bytes) {
	uint8_t *buff = new uint8_t[bytes];
	std::memset(buff, 0, bytes);
	pack.copyToBinaryPointer(buff, bytes);
	delete buff;
}
int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
	bool done = false;
	int bytercv = 0;
	while (!done) {
		bytercv = receiveHeader(pack);
		if (!isHeaderWellFormed(pack)) { // Reset all
			resetPacket(pack, bytercv);
		} else {
			int payloadSize = receivePayloadAndTail(pack, bytercv);
			if(payloadSize < 0){
				resetPacket(pack, pack.getPacketSize());
			}
			else{
				bytercv += payloadSize;
				done = true;
			}
		}
	}
	return bytercv;
Valerio Pastore's avatar
Valerio Pastore committed
}

int UDPProtocol::connectToClient() {
	int sockfd;

	// Creating socket file descriptor
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Valerio Pastore's avatar
Valerio Pastore committed
		perror("socket creation failed");
		return -1;
	}

	// Set timeout to the socket
	struct timeval tv;
	tv.tv_sec = std::numeric_limits<time_t>::max();
Valerio Pastore's avatar
Valerio Pastore committed
	tv.tv_usec = 0;
	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof tv);
Valerio Pastore's avatar
Valerio Pastore committed

	// Bind the socket with the server address
	if (bind(sockfd, (const struct sockaddr*) &srvaddr, sizeof(srvaddr)) < 0) {
Valerio Pastore's avatar
Valerio Pastore committed
		perror("bind failed");
		return -1;
	}

	this->srv_sock = sockfd;
Valerio Pastore's avatar
Valerio Pastore committed
	return sockfd;

}
int UDPProtocol::connectToServer() {
Valerio Pastore's avatar
Valerio Pastore committed
	int sockfd = 0;
	// Creating socket file descriptor
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Valerio Pastore's avatar
Valerio Pastore committed
		perror("socket creation failed");
		exit(EXIT_FAILURE);
	}

	printf("Connection made\n");
	this->cli_sock = sockfd;
Valerio Pastore's avatar
Valerio Pastore committed

	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;
bool UDPProtocol::isHeaderWellFormed(PacketLib::BasePacket &pack) {
	return true;
}
void 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)) {
		std::cerr << "Error: invalid IP address and port format: " << ip_port
				<< std::endl;
		exit(EXIT_FAILURE);
	}
Valerio Pastore's avatar
Valerio Pastore committed

	// 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);
}