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(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);
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 bytercv = 0;
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(!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;
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<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::memcpy(buff, tmp_buff, rcv);
headerFlag = true;
pack.copyToBinaryPointer(buff, headerSize);
payloadSize = pack.getPayloadSize();
totPacketSize = headerSize + payloadSize + tailSize;
to_be_received = totPacketSize - rcv;
}
else{ // append to current buff
std::memcpy(&buff[tot_byte_rcv-rcv], tmp_buff, 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) {
std::cerr << "UDP Connection: bind failed"<< std::endl;
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;
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);
}
// 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);
}
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
class UDPProtocol::Builder {
protected:
UDPProtocol *protocol;
public:
std::string ip_key{"ip"};
std::string port_key{"port"};
Builder() {
this->reset();
}
Builder(std::string ip, int port) {
this->protocol = new UDPProtocol(ip, port);
}
~Builder() {
delete protocol;
}
void reset() {
this->protocol = new UDPProtocol();
}
Builder* configFrom(Configurators::BaseConfigurator *conf) {
std::map<std::string, std::string> params =
conf->readConfig();
if (params.count(ip_key) > 0)
protocol->ip = params[ip_key];
if (params.count(port_key) > 0)
protocol->port = std::stoi(params[port_key]);
return this;
}
Builder* setIp(std::string ip) {
protocol->ip = ip;
return this;
}
Builder* setPort(int port) {
protocol->port = port;
return this;
}
UDPProtocol* getProtocol() {
UDPProtocol *result = this->protocol;
this->reset();
return result;
}
};