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

Valerio Pastore's avatar
Valerio Pastore committed
#include <TCP_Protocol.h>

Valerio Pastore's avatar
Valerio Pastore committed
using namespace inaf::oasbo::ConnectionProtocols;
astri's avatar
astri committed
TCPProtocol::TCPProtocol() :
		TCPProtocol("127.0.0.1", 9003) {
astri's avatar
astri committed
TCPProtocol::TCPProtocol(std::string ip, int prt) :
Valerio Pastore's avatar
Valerio Pastore committed
		ip(ip), port(prt), srv_sock(-1), cli_sock(-1) {
astri's avatar
astri committed
	host = ip + ":" + std::to_string(port);
Valerio Pastore's avatar
Valerio Pastore committed
	memset(&cliaddr, 0, sizeof(cliaddr));
	memset(&servaddr, 0, sizeof(servaddr));
astri's avatar
astri committed
}

TCPProtocol::~TCPProtocol() {
	closeConnectionToClient();
Valerio Pastore's avatar
Valerio Pastore committed
	::close(srv_sock);
Valerio Pastore's avatar
Valerio Pastore committed
}

int TCPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
	ssize_t headerSize = pack.getHeaderSize();
	uint8_t *buff = new uint8_t[pack.getPacketStructureByteSize()];
Valerio Pastore's avatar
Valerio Pastore committed
	ssize_t rec = ::recv(this->cli_sock, &buff[0], headerSize, MSG_WAITALL);
astri's avatar
astri committed
	if (rec == 0) { // connessione chiusa
astri's avatar
astri committed
		closeConnectionToClient();
Valerio Pastore's avatar
.  
Valerio Pastore committed
		delete[] buff;
		return 0;
	}
astri's avatar
astri committed
	if (rec != headerSize) {
Valerio Pastore's avatar
.  
Valerio Pastore committed
		delete[] buff;
Valerio Pastore's avatar
Valerio Pastore committed
		return -1;
	}
	pack.copyToBinaryPointer(buff, headerSize);
astri's avatar
astri committed
	if (!pack.isRecognizedHeader()) {
Valerio Pastore's avatar
Valerio Pastore committed
		resetPacket(pack, headerSize);
Valerio Pastore's avatar
.  
Valerio Pastore committed
		delete[] buff;
Valerio Pastore's avatar
Valerio Pastore committed
		return -1;
Valerio Pastore's avatar
Valerio Pastore committed

	int to_be_rcv = pack.getPayloadSize() + pack.getTailSize();
Valerio Pastore's avatar
Valerio Pastore committed
	rec += ::recv(this->cli_sock, &buff[headerSize], to_be_rcv, MSG_WAITALL);
astri's avatar
astri committed
	if (rec != to_be_rcv + headerSize) {
Valerio Pastore's avatar
Valerio Pastore committed
		resetPacket(pack, headerSize);
Valerio Pastore's avatar
.  
Valerio Pastore committed
		delete[] buff;
Valerio Pastore's avatar
Valerio Pastore committed
		return -1;
	}
	pack.copyToBinaryPointer(&buff[headerSize],
			pack.getPayloadSize() + pack.getTailSize(), headerSize);
Valerio Pastore's avatar
.  
Valerio Pastore committed
	delete[] buff;
Valerio Pastore's avatar
Valerio Pastore committed

	return rec;
}
Valerio Pastore's avatar
Valerio Pastore committed

int TCPProtocol::connectToClient() {
	return m_connectToCli(ip, port);
}

int TCPProtocol::closeConnectionToClient() {
	if (cli_sock != -1) {
		::close(cli_sock);
		cli_sock = -1;
	}
	return 1;
}

bool TCPProtocol::isConnectedToClient() const {
	return cli_sock > 0;
}

int TCPProtocol::m_connectToCli(std::string ip, int port) {
Valerio Pastore's avatar
Valerio Pastore committed
	// Creating socket file descriptor
Valerio Pastore's avatar
Valerio Pastore committed
	if (srv_sock == -1) { // bind
		if ((srv_sock = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
Valerio Pastore's avatar
Valerio Pastore committed
			std::cerr << "TCP socket on " << host << " failed" << std::endl;
			exit(EXIT_FAILURE);
		}
		servaddr.sin_family = AF_INET;
		servaddr.sin_addr.s_addr = ::inet_addr(ip.c_str());
		servaddr.sin_port = htons(port);
		if (bind(srv_sock, (struct sockaddr*) &servaddr, sizeof(servaddr))
				< 0) {
			std::cerr << "TCP CONNECTION on " << host << " Bind failed"
					<< std::endl;
			srv_sock = -1;
			exit(EXIT_FAILURE);
Valerio Pastore's avatar
Valerio Pastore committed
	}
Valerio Pastore's avatar
Valerio Pastore committed
	std::cout << "TCP CONNECTION: Waiting for connection on " << host
			<< std::endl;
Valerio Pastore's avatar
Valerio Pastore committed

	if (listen(srv_sock, 1) < 0) {
astri's avatar
astri committed
		std::cerr << "TCP CONNECTION:  Listen error" << std::endl;
astri's avatar
astri committed
		srv_sock = -1;
Valerio Pastore's avatar
Valerio Pastore committed
		return -1;
	}

Valerio Pastore's avatar
Valerio Pastore committed
	socklen_t clientAddressSize = sizeof(cliaddr);
	if ((cli_sock = accept(srv_sock, (struct sockaddr*) &cliaddr,
			(socklen_t*) &clientAddressSize)) < 0) {
		std::cerr << "TCP CONNECTION:  accept error" << std::endl;
		cli_sock = -1;
Valerio Pastore's avatar
Valerio Pastore committed
		return -1;
	}
Valerio Pastore's avatar
Valerio Pastore committed
	std::cout << "TCP CONNECTION:  Connected with " << inet_ntoa(cliaddr.sin_addr) << std::endl;
	return cli_sock;
Valerio Pastore's avatar
Valerio Pastore committed
}

Valerio Pastore's avatar
Valerio Pastore committed
void TCPProtocol::resetPacket(PacketLib::BasePacket &pack, int bytes) {
	uint8_t *buff = new uint8_t[bytes];
	std::memset(buff, 0, bytes);
astri's avatar
astri committed
	int toBeReset = std::min(
			static_cast<int>(pack.getPacketStructureByteSize()), bytes);
Valerio Pastore's avatar
Valerio Pastore committed
	pack.copyToBinaryPointer(buff, toBeReset);
Valerio Pastore's avatar
.  
Valerio Pastore committed
	delete[] buff;
Valerio Pastore's avatar
Valerio Pastore committed
}
Valerio Pastore's avatar
Valerio Pastore committed
std::string TCPProtocol::getHost() {
	return ip + ":" + std::to_string(port);
Valerio Pastore's avatar
Valerio Pastore committed
void TCPProtocol::setHost(std::string host) {
	std::string ip = { };
	int port = 0;
Valerio Pastore's avatar
Valerio Pastore committed
	if (split_ip_port(host, ip, port)) {
		setIp(ip);
		setPort(port);
Valerio Pastore's avatar
Valerio Pastore committed
	} else {
		std::cerr
				<< "Connection Protocol Error: invalid IP address and port format: "
				<< host << std::endl;
Valerio Pastore's avatar
Valerio Pastore committed
void TCPProtocol::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");
	}
Valerio Pastore's avatar
Valerio Pastore committed
	if (ok)
		this->ip = ip;

Valerio Pastore's avatar
Valerio Pastore committed
	this->host = ip + ":" + std::to_string(port);
Valerio Pastore's avatar
Valerio Pastore committed
void TCPProtocol::setPort(int port) {
	if (port > 1023 && port < 65535)
		this->port = port;
Valerio Pastore's avatar
Valerio Pastore committed
	else {
		std::cerr << "Connection Protocol Error: invalid port: " << port
Valerio Pastore's avatar
Valerio Pastore committed
				<< ", setting to 9003" << std::endl;
		this->port = 9003;
	}
Valerio Pastore's avatar
Valerio Pastore committed
	this->host = ip + ":" + std::to_string(port);
}

bool TCPProtocol::split_ip_port(const std::string &ip_port,
Valerio Pastore's avatar
Valerio Pastore committed
		std::string &ip_address, int &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);
Valerio Pastore's avatar
Valerio Pastore committed
	port = std::stoi(ip_port.substr(colon_pos + 1));
	return true;
}