Newer
Older
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <regex>
#include <limits>
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));
int UDPProtocol::receiveAtLeastHeaderSizeBytes(uint8_t *buff, int headerSize,
int packetSize) {
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);
}
}
return bytercv;
}
int UDPProtocol::receiveFromClient(PacketLib::BasePacket &pack) {
bool headerFlag = false;
int headerSize = pack.getHeaderSize();
int packSize = pack.getPacketStructureByteSize();
int tailSize = pack.getTailSize();
uint8_t *buff = new uint8_t[(packSize + headerSize) * headerSize]; // to avoid overflow
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) {
pack.copyToBinaryPointer(buff, headerSize); //copy the header into packet to be able to read it.
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);
delete buff;
delete tmp_buff;
resetPacket(pack, tot_byte_rcv);
return -1;
}
std::vector<uint8_t> 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;
}
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<time_t>::max();
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof tv);
if (bind(sockfd, (const struct sockaddr*) &srvaddr, sizeof(srvaddr)) < 0) {
int UDPProtocol::connectToServer() {
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "UDP Connection: socket creation failed " << std::endl;
std::cout << "UDP Connection: socket creation success " << std::endl;
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<int>(pack.getPacketStructureByteSize()), bytes);
pack.copyToBinaryPointer(buff, toBeReset);
delete buff;
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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)) {
// 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);