uni-lab/clab/client-server-system/server/utils.h
2026-03-08 18:57:07 +01:00

380 lines
8.8 KiB
C
Executable file

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#define SERVER_BACKLOG 100
#define INFO_WAIT_TIME 2
#define TCP_WAIT_TIME 3
#define FIRST_ALIVE_TIMEOUT 3
#define ALIVE_TIMEOUT 2
#define M 3
/*--------------TIPUS DE PAQUETS-------------*/
/* Paquets de la fase de registre */
unsigned char REG_REQ = 0x00;
unsigned char REG_INFO = 0x01;
unsigned char REG_ACK = 0x02;
unsigned char INFO_ACK = 0x03;
unsigned char REG_NACK = 0x04;
unsigned char INFO_NACK = 0x05;
unsigned char REG_REJ = 0x06;
/* Paquets per a la comunicació periòdica */
unsigned char ALIVE = 0x10;
unsigned char ALIVE_REJ = 0x11;
/* Paquets per a la transferència de dades amb el servidor */
unsigned char SEND_DATA = 0x20;
unsigned char SET_DATA = 0x21;
unsigned char GET_DATA = 0x22;
unsigned char DATA_ACK = 0x23;
unsigned char DATA_NACK = 0x24;
unsigned char DATA_REJ = 0x25;
/*---------------ESTATS----------------*/
unsigned char DISCONNECTED = 0xa0;
unsigned char NOT_REGISTERED = 0xa1;
unsigned char WAIT_ACK_REG = 0xa2;
unsigned char WAIT_INFO = 0xa3;
unsigned char WAIT_ACK_INFO = 0xa4;
unsigned char REGISTERED = 0xa5;
unsigned char SEND_ALIVE = 0xa6;
/*-------------STRUCTS-------------*/
typedef struct client_info
{
unsigned char state;
char id[13];
char randNum[9];
char elems[50];
char ip[16];
unsigned short tcpPort;
time_t lastAlive;
} client_info;
typedef struct clients_db
{
client_info *clients;
int length;
} clients_db;
typedef struct udp_pdu
{
unsigned char pack;
char id[13];
char randNum[9];
char data[61];
} udp_pdu;
typedef struct tcp_pdu
{
unsigned char pack;
char id[13];
char randNum[9];
char elem[8];
char value[16];
char data[80];
} tcp_pdu;
typedef struct config
{
char *id;
int udpPort;
int tcpPort;
} config;
typedef struct reg_thread_args
{
udp_pdu pdu;
int socket;
struct sockaddr_in clientAddress;
} reg_thread_args;
int generateRandNum(int min, int max)
{
srand(time(0));
return rand() % (max + 1 - min) + min;
}
/*--------------------------------------------*/
/*---------------DEBUG UTILS------------------*/
/*--------------------------------------------*/
int DEBUG_ON = 0;
void debugPrint(const char *message)
{
if (DEBUG_ON)
{
printf("%s => %s\n", __TIME__, message);
fflush(stdout);
}
}
void check(int result, const char *message)
{
if (result < 0)
{
perror(message);
exit(EXIT_FAILURE);
}
}
/*--------------------------------------------*/
/*---------------DATABASE UTILS---------------*/
/*--------------------------------------------*/
int isAuthorized(clients_db *db, const char *id)
{
for (int i = 0; i < db->length; i++)
if (strcmp(id, db->clients[i].id) == 0)
return i;
return -1;
}
void disconnectClient(client_info *client)
{
if (client->state != DISCONNECTED)
{
char debugMessage[60] = {'\0'};
sprintf(debugMessage, "Client %s pasa a l'estat DISCONNECTED", client->id);
debugPrint(debugMessage);
}
client->state = DISCONNECTED;
memset(client->elems, '\0', sizeof(client->elems));
memset(client->ip, '\0', sizeof(client->ip));
memset(client->randNum, '\0', sizeof(client->randNum));
client->tcpPort = -1;
client->lastAlive = -1;
}
int shareClientsInfo(clients_db *db)
{
int shmid;
if ((shmid = shmget(IPC_PRIVATE, db->length * sizeof(client_info), IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1)
return -1;
client_info *tmp;
if ((tmp = shmat(shmid, (void *)0, 0)) == (void *)-1)
return -1;
for (int i = 0; i < db->length; i++)
tmp[i] = db->clients[i];
free(db->clients);
db->clients = tmp;
return 0;
}
int hasElem(const char *elem, client_info *client)
{
char cpy[50] = {'\0'};
strcpy(cpy, client->elems);
char *token = strtok(cpy, ";");
while (token != NULL)
{
if (strcmp(elem, token) == 0)
return 1;
token = strtok(NULL, ";");
}
return 0;
}
/*--------------------------------------------*/
/*---------------SOCKETS UTILS----------------*/
/*--------------------------------------------*/
int sendUdp(int sock, unsigned char pack, char id[13], char randNum[9], char data[61], struct sockaddr_in address)
{
udp_pdu pdu;
pdu.pack = pack;
strcpy(pdu.id, id);
strcpy(pdu.randNum, randNum);
strcpy(pdu.data, data);
return sendto(sock, &pdu, sizeof(udp_pdu), 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
}
int sendTcp(int sock, unsigned char pack, char id[13], char randNum[9], char elem[8], char value[16], char info[80])
{
tcp_pdu pdu;
pdu.pack = pack;
strcpy(pdu.id, id);
strcpy(pdu.randNum, randNum);
strcpy(pdu.elem, elem);
strcpy(pdu.value, value);
strcpy(pdu.data, info);
return send(sock, &pdu, sizeof(tcp_pdu), 0);
}
int selectIn(int sock, fd_set *inputs, int timeout)
{
struct timeval t;
t.tv_sec = timeout;
t.tv_usec = 0;
FD_ZERO(inputs);
FD_SET(sock, inputs);
return select(sock + 1, inputs, NULL, NULL, &t);
}
int bindTo(int sock, uint16_t port)
{
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = INADDR_ANY;
return bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
}
int connectTo(int sock, const char *ip, unsigned short port)
{
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = inet_addr(ip);
return connect(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
}
int getPort(int fd)
{
struct sockaddr_in address;
socklen_t len = sizeof(struct sockaddr_in);
int port = 0;
memset(&address, 0, sizeof(struct sockaddr_in));
if (getsockname(fd, (struct sockaddr *)&address, &len) == -1)
return -1;
port = ntohs(address.sin_port);
return port;
}
/*----------------------------------------*/
/*-------------READING UTILS--------------*/
/*----------------------------------------*/
char *getLine(FILE *fp)
{
size_t len = 3;
char *line = (char *)malloc(len * sizeof(char));
int c = fgetc(fp);
int i = 0;
while (c != '\n' && c != EOF)
{
line[i] = c;
i++;
if (i == len)
{
len++;
line = (char *)realloc(line, len * sizeof(char));
}
c = fgetc(fp);
}
if (i == 0)
{
free(line);
return NULL;
}
line[i] = '\0';
return line;
}
char *trim(char *str)
{
char *end;
/*left trim*/
while (isspace((unsigned char)*str))
str++;
if (*str == 0) /*Es tot espais*/
return str;
/*Right trim*/
end = str + strlen(str) - 1;
while (end > str && (isspace((unsigned char)*end) || (unsigned char)*end == '\n'))
end--;
end[1] = '\0';
return str;
}
char *getCfgLineInfo(FILE *fp)
{
char *line = getLine(fp);
if (line == NULL)
return NULL;
char *tmp = strrchr(line, '=');
tmp++;
char *info = trim(tmp);
if (strlen(info) <= 0)
return NULL;
return info;
}
int readConfig(config *cfg, const char *filename)
{
char *attrs[3];
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL)
return -1;
for (int i = 0; i < 3; i++)
{
if ((attrs[i] = getCfgLineInfo(fp)) == NULL)
{
fclose(fp);
return -1;
}
}
cfg->id = attrs[0];
cfg->udpPort = atoi(attrs[1]);
cfg->tcpPort = atoi(attrs[2]);
fclose(fp);
return 0;
}
int readDb(clients_db *db, const char *filename)
{
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL)
return -1;
client_info *clients = (client_info *)malloc(sizeof(client_info));
char *line;
int len = 1, i = 0;
while ((line = getLine(fp)) != NULL)
{
if (i == len)
{
len++;
clients = (client_info *)realloc(clients, len * sizeof(client_info));
}
client_info client;
memset(&client, 0, sizeof(client_info));
client.state = DISCONNECTED;
strcpy(client.id, line);
memset(client.elems, '\0', sizeof(client.elems));
memset(client.ip, '\0', sizeof(client.ip));
memset(client.randNum, '\0', sizeof(client.randNum));
client.tcpPort = -1;
client.lastAlive = -1;
clients[i] = client;
i++;
}
if (i == 0)
{
fclose(fp);
free(clients);
return -1;
}
fclose(fp);
db->clients = clients;
db->length = len;
return 0;
}