main
Marc Cane 2026-04-28 22:04:35 +02:00
commit 26e3fc66a6
10 changed files with 2098 additions and 0 deletions

7
P2P/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.5)
project(P2P)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(SOURCE_FILES ../nodelumi2/MIp2-lumi.h ../nodelumi2/MIp2-lumi.c MIp2-p2p.c MIp2-mi.c MIp2-mi.h)
add_executable(P2P ${SOURCE_FILES})

574
P2P/MIp2-mi.c Normal file
View File

@ -0,0 +1,574 @@
/**************************************************************************/
/* */
/* P1 - MI amb sockets TCP/IP - Part I */
/* Fitxer mi.c que implementa la capa d'aplicació de MI, sobre la capa de */
/* transport TCP (fent crides a la interfície de la capa TCP -sockets-). */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Inclusió de llibreries, p.e. #include <sys/types.h> o #include "meu.h" */
/* (si les funcions externes es cridessin entre elles, faria falta fer */
/* un #include "MIp1v4-mi.h") */
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include "MIp2-mi.h"
#include <ifaddrs.h>
/* Definició de constants, p.e., #define MAX_LINIA 150 */
#define TECLAT 0
#define MAX_FD 2
#define MAX_MESSAGE_SIZE 303
#define NOM_INTERFICIE "lo" //Aquest valor s'ha de canviar si es vol fer funcionar la funcio MI_ObtenirInfoServidor()
#define IP_LENGTH 16
/* Declaració de funcions internes que es fan servir en aquest fitxer */
/* (les seves definicions es troben més avall) per així fer-les conegudes */
/* des d'aqui fins al final de fitxer. */
int TCP_CreaSockClient(const char *IPloc, int portTCPloc);
int TCP_CreaSockServidor(const char *IPloc, int portTCPloc);
int TCP_DemanaConnexio(int Sck, const char *IPrem, int portTCPrem);
int TCP_AcceptaConnexio(int Sck, char *IPrem, int *portTCPrem);
int TCP_Envia(int Sck, const char *SeqBytes, int LongSeqBytes);
int TCP_Rep(int Sck, char *SeqBytes, int LongSeqBytes);
int TCP_TancaSock(int Sck);
int TCP_TrobaAdrSockLoc(int Sck, char *IPloc, int *portTCPloc);
int TCP_TrobaAdrSockRem(int Sck, char *IPrem, int *portTCPrem);
int HaArribatAlgunaCosa(const int *LlistaSck, int LongLlistaSck);
void MostraError(const char *text);
/* Definicio de funcions EXTERNES, és a dir, d'aquelles que en altres */
/* fitxers externs es faran servir. */
/* En termes de capes de l'aplicació, aquest conjunt de funcions externes */
/* formen la interfície de la capa MI. */
/* Inicia lescolta de peticions remotes de conversa a través dun nou */
/* socket TCP en el #port “portTCPloc” i una @IP local qualsevol (és a */
/* dir, crea un socket “servidor” o en estat descolta listen ). */
/* Retorna -1 si hi ha error; lidentificador del socket descolta de MI */
/* creat si tot va bé. */
int MI_IniciaEscPetiRemConv(int portTCPloc)
{
return TCP_CreaSockServidor("0.0.0.0", portTCPloc);
}
/* Escolta indefinidament fins que arriba una petició local de conversa */
/* a través del teclat o bé una petició remota de conversa a través del */
/* socket descolta de MI didentificador “SckEscMI” (un socket */
/* “servidor”). */
/* Retorna -1 si hi ha error; 0 si arriba una petició local; SckEscMI si */
/* arriba una petició remota. */
int MI_HaArribatPetiConv(int SckEscMI)
{
int FDs[] = {TECLAT, SckEscMI};
return HaArribatAlgunaCosa(FDs, MAX_FD);
}
/* Crea una conversa iniciada per una petició local que arriba a través */
/* del teclat: crea un socket TCP “client” (en un #port i @IP local */
/* qualsevol), a través del qual fa una petició de conversa a un procés */
/* remot, el qual les escolta a través del socket TCP ("servidor") d'@IP */
/* “IPrem” i #port “portTCPrem” (és a dir, crea un socket “connectat” o */
/* en estat establert established ). Aquest socket serà el que es farà */
/* servir durant la conversa. */
/* Omple “IPloc*” i “portTCPloc*” amb, respectivament, l@IP i el #port */
/* TCP del socket del procés local. */
/* El nickname local “NicLoc” i el nickname remot són intercanviats amb */
/* el procés remot, i somple “NickRem*” amb el nickname remot. El procés */
/* local és qui inicia aquest intercanvi (és a dir, primer senvia el */
/* nickname local i després es rep el nickname remot). */
/* "IPrem" i "IPloc*" són "strings" de C (vectors de chars imprimibles */
/* acabats en '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* "NicLoc" i "NicRem*" són "strings" de C (vectors de chars imprimibles */
/* acabats en '\0') d'una longitud màxima de 300 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; lidentificador del socket de conversa de */
/* MI creat si tot va bé. */
int MI_DemanaConv(const char *IPrem, int portTCPrem, char *IPloc, int *portTCPloc, const char *NicLoc, char *NicRem)
{
int sock;
sock = TCP_CreaSockClient("0.0.0.0", 0);
if (sock == -1) return -1;
if (TCP_DemanaConnexio(sock,IPrem, portTCPrem) == -1) return -1;
if(TCP_TrobaAdrSockLoc(sock, IPloc, portTCPloc) == -1) return -1;
if (MI_EnviaNickname(sock,NicLoc) == -1)
return -1;
char buff[300];
int long_nom = MI_RepLinia(sock,buff);
if (long_nom == -1 ) return -1;
//strncpy(NicRem, buff, long_nom);
strcpy(NicRem,buff);
//strcpy(NicRem,"setaci");
return sock;
}
/* Crea una conversa iniciada per una petició remota que arriba a través */
/* del socket descolta de MI didentificador “SckEscMI” (un socket */
/* “servidor”): accepta la petició i crea un socket (un socket */
/* “connectat” o en estat establert established ), que serà el que es */
/* farà servir durant la conversa. */
/* Omple “IPrem*”, “portTCPrem*”, “IPloc*” i “portTCPloc*” amb, */
/* respectivament, l@IP i el #port TCP del socket del procés remot i del */
/* socket del procés local. */
/* El nickname local “NicLoc” i el nickname remot són intercanviats amb */
/* el procés remot, i somple “NickRem*” amb el nickname remot. El procés */
/* remot és qui inicia aquest intercanvi (és a dir, primer es rep el */
/* nickname remot i després senvia el nickname local). */
/* "IPrem*" i "IPloc*" són "strings" de C (vectors de chars imprimibles */
/* acabats en '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* "NicLoc" i "NicRem*" són "strings" de C (vectors de chars imprimibles */
/* acabats en '\0') d'una longitud màxima de 300 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; lidentificador del socket de conversa */
/* de MI creat si tot va bé. */
int MI_AcceptaConv(int SckEscMI, char *IPrem, int *portTCPrem, char *IPloc, int *portTCPloc, const char *NicLoc, char *NicRem)
{
//if (TCP_TrobaAdrSockRem(SckEscMI, IPrem, portTCPrem) == -1) return -1;
int sock;
sock = TCP_AcceptaConnexio(SckEscMI,IPrem,portTCPrem);
if (sock == -1)
return -1;
if (TCP_TrobaAdrSockLoc(sock, IPloc, portTCPloc) == -1)
return -1;
if (TCP_TrobaAdrSockRem(sock, IPrem, portTCPrem) == -1)
return -1;
char buff[300];
int long_nom = MI_RepLinia(sock,buff);
if (long_nom == -1 ) return -1;
if (MI_EnviaNickname(sock,NicLoc) == -1)
return -1;
//strncpy(NicRem, buff, long_nom);
strcpy(NicRem,buff);
return sock;
}
/* Escolta indefinidament fins que arriba una línia local de conversa a */
/* través del teclat o bé una línia remota de conversa a través del */
/* socket de conversa de MI didentificador “SckConvMI” (un socket */
/* "connectat”). */
/* Retorna -1 si hi ha error; 0 si arriba una línia local; SckConvMI si */
/* arriba una línia remota. */
int MI_HaArribatLinia(int SckConvMI)
{
int FDs[] = {TECLAT, SckConvMI};
return HaArribatAlgunaCosa(FDs, MAX_FD);
}
/* Envia a través del socket de conversa de MI didentificador */
/* “SckConvMI” (un socket “connectat”) la línia “Linia” escrita per */
/* lusuari local. */
/* "Linia" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0'), no conté el caràcter fi de línia ('\n') i té una longitud */
/* màxima de 300 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; el nombre de caràcters n de la línia */
/* enviada (sense el \0) si tot va bé (0 <= n <= 299). */
int MI_EnviaLinia(int SckConvMI, const char *Linia)
{
char missatge[MAX_MESSAGE_SIZE+1], tipus = 'L';
int miss_len = strlen(Linia);
sprintf(missatge,"%c%.3d%s",tipus,miss_len,Linia);
return TCP_Envia(SckConvMI, missatge, miss_len+4);
}
/* Envia a través del socket de conversa de MI didentificador */
/* “SckConvMI” (un socket “connectat”) el nickname "Nick" escrit per */
/* lusuari local. */
/* "Nick" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0'), no conté el caràcter fi de línia ('\n') i té una longitud */
/* màxima de 300 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; el nombre de caràcters n del nickname */
/* enviat (sense el \0) si tot va bé (0 <= n <= 299). */
int MI_EnviaNickname(int SckConvMI, const char *Nick)
{
char nickname[MAX_MESSAGE_SIZE+1], tipus = 'N';
int miss_len = strlen(Nick);
sprintf(nickname,"%c%.3d%s",tipus,miss_len,Nick);
return TCP_Envia(SckConvMI, nickname, miss_len+4);
}
/* Rep a través del socket de conversa de MI didentificador “SckConvMI” */
/* (un socket “connectat”) una línia escrita per lusuari remot, amb la */
/* qual omple “Linia”, o bé detecta lacabament de la conversa per part */
/* de lusuari remot. */
/* "Linia*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0'), no conté el caràcter fi de línia ('\n') i té una longitud */
/* màxima de 300 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; -2 si lusuari remot acaba la conversa; el */
/* nombre de caràcters n de la línia rebuda (sense el \0) si tot va bé */
/* (0 <= n <= 299). */
int MI_RepLinia(int SckConvMI, char *Linia)
{
int res;
char buffer[MAX_MESSAGE_SIZE];
res = TCP_Rep(SckConvMI, buffer, sizeof(buffer));
if (res > 0){
char len[3];
strncpy(len, buffer+1, sizeof(len));
int long_miss = atoi(len);
buffer[res]='\0';
strcpy(Linia, buffer+4);
res = long_miss;
}
else if (res == 0) res=-2;
return res;
}
/* Acaba la conversa associada al socket de conversa de MI */
/* didentificador “SckConvMI” (un socket “connectat”). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int MI_AcabaConv(int SckConvMI)
{
return TCP_TancaSock(SckConvMI);
}
/* Acaba lescolta de peticions remotes de conversa que arriben a través */
/* del socket descolta de MI didentificador “SckEscMI” (un socket */
/* “servidor”). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int MI_AcabaEscPetiRemConv(int SckEscMI)
{
return TCP_TancaSock(SckEscMI);
}
///******************************** FUNCIONS ADICIONALS DE LA CAPA MI ********************************///
/* Donat un socket descriptor sock, ens troba la IP i el port a on es */
/* troba. */
/* "IPloc" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* Retorna -1 si algo ha anat malament, 0 si no hi ha hagut problemes */
int MI_ObtenirInfoServidor(int sock, char *IPloc, int *portTCPloc){
if (TCP_TrobaAdrSockLoc(sock, IPloc, portTCPloc) == -1) return -1; //Aixo ens dona el port pero no la IP
///**** Fragment de codi extret de: https://stackoverflow.com/questions/20800319/how-do-i-get-my-ip-address-in-c-on-linux ****///
struct ifaddrs *addrs,*tmp;
getifaddrs(&addrs); //funcio que ens retornara una llista encadenada d'interficies
tmp = addrs;
int trobat = 0;
while (tmp && !trobat) //Mentre ens quedin candidats i no el trobem
{
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) //Si la interficie es IPv4
{
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
if (strcmp(tmp->ifa_name,NOM_INTERFICIE) == 0) { //Si hem trobat la nostre interficie
strcpy(IPloc,inet_ntoa(pAddr->sin_addr));
trobat = 1;
}
}
tmp = tmp->ifa_next;
}
freeifaddrs(addrs);
///***************************************************************************************************************************///
return 0;
}
/**************************************************************************/
/* */
/* P1 - MI amb sockets TCP/IP - Part I */
/* Versio numero 1.337 */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Definicio de funcions */
/* Crea un socket TCP “client” a l@IP “IPloc” i #port TCP “portTCPloc” */
/* (si “IPloc” és “0.0.0.0” i/o “portTCPloc” és 0 es fa/farà una */
/* assignació implícita de l@IP i/o del #port TCP, respectivament). */
/* "IPloc" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* Retorna -1 si hi ha error; lidentificador del socket creat si tot */
/* va bé. */
int TCP_CreaSockClient(const char *IPloc, int portTCPloc)
{
int sockdesc;
if ((sockdesc = socket(AF_INET,SOCK_STREAM,0)) == -1){
MostraError("Error creació socket client");
return -1;
}
else{
struct sockaddr_in adr;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPloc);
adr.sin_port = htons(portTCPloc);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
if (bind(sockdesc,(struct sockaddr*)&adr,sizeof(adr))==-1){
MostraError("Error bind client");
return -1;
}
}
return sockdesc;
}
/* Crea un socket TCP “servidor” (o en estat descolta listen ) a */
/* l@IP “IPloc” i #port TCP “portTCPloc” (si “IPloc” és “0.0.0.0” i/o */
/* “portTCPloc” és 0 es fa una assignació implícita de l@IP i/o del */
/* #port TCP, respectivament). */
/* "IPloc" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; lidentificador del socket creat si tot */
/* va bé. */
int TCP_CreaSockServidor(const char *IPloc, int portTCPloc)
{
int sockdesc;
if ((sockdesc = socket(AF_INET,SOCK_STREAM,0)) == -1){
MostraError("Error creació socket servidor");
return -1;
}
struct sockaddr_in adr;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPloc);
adr.sin_port = htons(portTCPloc);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
if (bind(sockdesc,(struct sockaddr*)&adr,sizeof(adr))==-1){
MostraError("Error bind servidor");
return -1;
}
if((listen(sockdesc,3))==-1){
MostraError("Error bind servidor");
return -1;
}
return sockdesc;
}
/* El socket TCP “client” didentificador “Sck” demana una connexió al */
/* socket TCP “servidor” d@IP “IPrem” i #port TCP “portTCPrem” (si tot */
/* va bé es diu que el socket “Sck” passa a lestat “connectat” o */
/* establert established ). */
/* "IPrem" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int TCP_DemanaConnexio(int Sck, const char *IPrem, int portTCPrem)
{
struct sockaddr_in adr;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPrem);
adr.sin_port = htons(portTCPrem);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
if((connect(Sck,(struct sockaddr*)&adr,sizeof(adr)))==-1){
char buff[100];
snprintf(buff, sizeof(buff), "Error: no s'ha pogut connectar amb %s", IPrem);
MostraError(buff);
return -1;
}
return 1;
}
/* El socket TCP “servidor” didentificador “Sck” accepta fer una */
/* connexió amb un socket TCP “client” remot, i crea un “nou” socket, */
/* que és el que es farà servir per enviar i rebre dades a través de la */
/* connexió (es diu que aquest nou socket es troba en lestat “connectat” */
/* o establert established ; el nou socket té la mateixa adreça que */
/* “Sck”). */
/* Omple “IPrem*” i “portTCPrem*” amb respectivament, l@IP i el #port */
/* TCP del socket remot amb qui sha establert la connexió. */
/* "IPrem*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; lidentificador del socket connectat creat */
/* si tot va bé. */
int TCP_AcceptaConnexio(int Sck, char *IPrem, int *portTCPrem)
{
struct sockaddr_in adr;
int scon;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPrem);
adr.sin_port = htons(*portTCPrem);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
size_t long_adr = sizeof(adr);
if((scon=accept(Sck,(struct sockaddr*)&adr, &long_adr))==-1)
{
char buff[100];
snprintf(buff, sizeof(buff), "Error: no s'ha pogut acceptar la connexio de %s", IPrem);
MostraError(buff);
return -1;
}
return scon;
}
/* Envia a través del socket TCP “connectat” didentificador “Sck” la */
/* seqüència de bytes escrita a “SeqBytes” (de longitud “LongSeqBytes” */
/* bytes) cap al socket TCP remot amb qui està connectat. */
/* "SeqBytes" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud >= LongSeqBytes bytes. */
/* Retorna -1 si hi ha error; el nombre de bytes enviats si tot va bé. */
int TCP_Envia(int Sck, const char *SeqBytes, int LongSeqBytes)
{
return write(Sck,SeqBytes,LongSeqBytes);
}
/* Rep a través del socket TCP “connectat” didentificador “Sck” una */
/* seqüència de bytes que prové del socket remot amb qui està connectat, */
/* i lescriu a “SeqBytes*” (que té una longitud de “LongSeqBytes” bytes),*/
/* o bé detecta que la connexió amb el socket remot ha estat tancada. */
/* "SeqBytes*" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud <= LongSeqBytes bytes. */
/* Retorna -1 si hi ha error; 0 si la connexió està tancada; el nombre de */
/* bytes rebuts si tot va bé. */
int TCP_Rep(int Sck, char *SeqBytes, int LongSeqBytes)
{
return read(Sck,SeqBytes,LongSeqBytes);
}
/* Sallibera (sesborra) el socket TCP didentificador “Sck”; si “Sck” */
/* està connectat es tanca la connexió TCP que té establerta. */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int TCP_TancaSock(int Sck)
{
return close(Sck);
}
/* Donat el socket TCP didentificador “Sck”, troba ladreça daquest */
/* socket, omplint “IPloc*” i “portTCPloc*” amb respectivament, la seva */
/* @IP i #port TCP. */
/* "IPloc*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int TCP_TrobaAdrSockLoc(int Sck, char *IPloc, int *portTCPloc)
{
struct sockaddr_in adr;
socklen_t long_adr = sizeof(adr);
int res;
if( (res = getsockname(Sck, (struct sockaddr*)&adr, &long_adr)) == -1){
MostraError("Error al trobar la direccio local");
return -1;
}
strcpy(IPloc,inet_ntoa(adr.sin_addr));
*portTCPloc = ntohs(adr.sin_port);
return res;
}
/* Donat el socket TCP “connectat” didentificador “Sck”, troba ladreça */
/* del socket remot amb qui està connectat, omplint “IPrem*” i */
/* “portTCPrem*” amb respectivament, la seva @IP i #port TCP. */
/* "IPrem*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int TCP_TrobaAdrSockRem(int Sck, char *IPrem, int *portTCPrem)
{
struct sockaddr_in adr;
socklen_t long_adr = sizeof(adr);
int res;
if ( (res = getpeername(Sck, (struct sockaddr*)&adr, &long_adr)) == -1) {
MostraError("Error al trobar la direccio remota");
return -1;
}
strcpy(IPrem,inet_ntoa(adr.sin_addr));
*portTCPrem = ntohs(adr.sin_port);
return res;
}
/* Examina simultàniament i sense límit de temps (una espera indefinida) */
/* els sockets (poden ser TCP, UDP i stdin) amb identificadors en la */
/* llista “LlistaSck” (de longitud “LongLlistaSck” sockets) per saber si */
/* hi ha arribat alguna cosa per ser llegida. */
/* "LlistaSck" és un vector d'enters d'una longitud >= LongLlistaSck */
/* Retorna -1 si hi ha error; si arriba alguna cosa per algun dels */
/* sockets, retorna lidentificador daquest socket. */
int HaArribatAlgunaCosa(const int *LlistaSck, int LongLlistaSck)
{
/*struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;*/ //estructura per definir un timeout de 30 segons al select
fd_set set;
FD_ZERO(&set);
int i = 0;
while (i<LongLlistaSck){
FD_SET(LlistaSck[i],&set);
i++;
}
int smax = LlistaSck[i-1]+1;
if (select(smax,&set,NULL,NULL,NULL) == -1){
MostraError("Error a la espera d'arribar alguna cosa");
return -1;
}
int ifd=0;
while( ifd < LongLlistaSck && !FD_ISSET(LlistaSck[ifd],&set) ) ifd++;
return LlistaSck[ifd];
}
/* Escriu un missatge de text al flux derror estàndard stderr, format */
/* pel text “Text”, un “:”, un espai en blanc, un text que descriu el */
/* darrer error produït en una crida de sockets, i un canvi de línia. */
void MostraError(const char *text)
{
fprintf(stderr, "%s: %s\n", text, strerror(errno));
}
/* Si ho creieu convenient, feu altres funcions... */

29
P2P/MIp2-mi.h Normal file
View File

@ -0,0 +1,29 @@
/**************************************************************************/
/* */
/* P1 - MI amb sockets TCP/IP - Part I */
/* Fitxer capçalera de mi.c */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Declaració de funcions externes de mi.c, és a dir, d'aquelles que es */
/* faran servir en un altre fitxer extern, p.e., MIp1-p2p.c; el fitxer */
/* extern farà un #include del fitxer .h a l'inici, i així les funcions */
/* seran conegudes en ell. */
/* En termes de capes de l'aplicació, aquest conjunt de funcions externes */
/* formen la interfície de la capa MI. */
int MI_IniciaEscPetiRemConv(int portTCPloc);
int MI_HaArribatPetiConv(int SckEscMI);
int MI_DemanaConv(const char *IPrem, int portTCPrem, char *IPloc, int *portTCPloc, const char *NicLoc, char *NicRem);
int MI_AcceptaConv(int SckEscMI, char *IPrem, int *portTCPrem, char *IPloc, int *portTCPloc, const char *NicLoc, char *NicRem);
int MI_HaArribatLinia(int SckConvMI);
int MI_EnviaLinia(int SckConvMI, const char *Linia);
int MI_EnviaNickname(int SckConvMI, const char *Linia);
int MI_RepLinia(int SckConvMI, char *Linia);
int MI_AcabaConv(int SckConvMI);
int MI_AcabaEscPetiRemConv(int SckEscMI);
int MI_ObtenirInfoServidor(int sock, char *IPloc, int *portTCPloc);

248
P2P/MIp2-p2p.c Normal file
View File

@ -0,0 +1,248 @@
/**************************************************************************/
/* */
/* P1 - MI amb sockets TCP/IP - Part I */
/* Fitxer p2p.c que implementa la interfície aplicació-usuari de */
/* l'aplicació de MI, sobre la capa d'aplicació de MI (fent crides a la */
/* interfície de la capa MI -fitxers mi.c i mi.h-). */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Inclusió de llibreries, p.e. #include <stdio.h> o #include "meu.h" */
/* Incloem "MIp1v4-mi.h" per poder fer crides a la interfície de MI */
#include "MIp2-mi.h"
#include "../nodelumi2/MIp2-lumi.h"
#include "stdio.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
/* Definició de constants, p.e., #define MAX_LINIA 150 */
#define MAX_MISSATGE 300
#define IP_LENGTH 16
#define TECLAT 0
#define MARCA_FI "/end"
int main(int argc,char *argv[])
{
/* Declaració de variables, p.e., int n; */
/*int sesc, scon, slumi; //socket descriptor dels sockets
int port=0, port_loc, port_rem; //port: farà de port local o remot segons la situació. Les variables port_loc i port_rem son per claretat de codi.
char IPloc[IP_LENGTH], IPrem[IP_LENGTH]; //IPs local i remota
char adrLUMIloc[MAX_LEN_DOMINI+MAX_USER_NICK+1], adrLUMIrem[MAX_LEN_DOMINI+MAX_USER_NICK+1];
char nickname_l[MAX_MISSATGE], nickname_r[MAX_MISSATGE]; //Nicknames local i remot
char vols_continuar; //Eleccio de l'usuari
int usuari_vol_conversa=1, connectat = 0; //Boolea per saber si l'usuari vol seguir parlant*/
int sesc, scon, slumi, desc; //descriptors dels sockets
int port_loc, port_rem; //port: farà de port local o remot segons la situació. Les variables port_loc i port_rem son per claretat de codi.
char IPloc[IP_LENGTH], IPrem[IP_LENGTH], IPnode[IP_LENGTH]; //IPs local i remota i del node
char adrLUMIloc[MAX_LEN_DOMINI+MAX_USER_NICK+1], adrLUMIrem[MAX_LEN_DOMINI+MAX_USER_NICK+1];
char nickname_l[MAX_MISSATGE], nickname_r[MAX_MISSATGE]; //Nicknames local i remot
char domini_l[MAX_LEN_DOMINI], domini_r[MAX_LEN_DOMINI];
char resposta[MAX_MISSATGE_PLUMI+1];
char vols_continuar; //Eleccio de l'usuari
int fitxer_log;
int usuari_vol_conversa=1, connectat = 0, res; //Boolea per saber si l'usuari vol seguir parlant
int llistaDesc[3];
/* Expressions, estructures de control, crides a funcions, etc. */
printf("Entra la teva @MI: ");
scanf("%s", adrLUMIloc);
printf("Quin nom d'usuari vols fer servir: ");
scanf("%s", nickname_l);
//LUMI_DescodificarAdreca(adrLUMIloc,nickname_l,domini_l);
if ((slumi = LUMI_InicialitzarAgent("0.0.0.0",0, &fitxer_log, adrLUMIloc, IPnode)) < 0){
//Apagar tot
close(slumi);
return 1;
}
res = LUMI_EnviaPeticioRegistre(slumi, adrLUMIloc);
if (res == 0) printf("S'ha rebut un missatge de confirmacio inesperat\n");
else if (res == -1) printf("Error a l'hora d'enviar la peticio de registre\n");
else if (res == -2) printf("Format del missatge de registre enviat incorrecte\n");
else if (res == -3) printf("L'usuari que has indicat no existeix\n");
else if (res == -4) printf("L'usuari que has indicat ja esta registrat\n");
else if (res == -5) printf("Temps d'espera de peticio de registre esgotat\n");
else if (res == -6) printf("Format del missatge de resposta incorrecte\n");
else printf("Error desconegut\n");
while(usuari_vol_conversa){
connectat = 0;
if ((sesc = MI_IniciaEscPetiRemConv(0)) == -1) return 1;
if (MI_ObtenirInfoServidor(sesc,IPloc,&port_loc) == -1) return 1;
//printf("\nLa IP necessaria per comunicar-se amb aquest terminal es: %s\nEl port assignat per comunicar-se amb aquest terminal es: %i\n\n", IPloc, port_loc);
llistaDesc[0]=TECLAT;
llistaDesc[1]=sesc;
llistaDesc[2]=slumi;
printf("Si vols iniciar conversa amb algu, entra la seva @MI, altrament espera:\n");
while(connectat==0){
desc = HaArribatAlgunaCosaEnTemps(llistaDesc, 3, 0);
if(desc == slumi){
res = LUMI_RepLiniaDe(slumi, NULL, NULL, resposta, sizeof(resposta));
if(res==-2) printf("S'ha rebut una linia mal formatada\n");
else if(res<=0) printf("S'ha produit un error al rebre un missatge de LUMI\n");
res = LUMI_DescodificarMissatge(resposta[0], resposta, adrLUMIrem, NULL, NULL);
if(res==-1) printf("Error al descodificar un missatge LUMI\n");
if (resposta[0] == 'S') {
//printf("En markus ha respos a la peticio S\n");
res = LUMI_EnviaRespostaServeiLocalitzacio(slumi, adrLUMIrem, IPloc, port_loc);
if(res<=0) printf("Error al respondre peticio de localitzacio\n");
}
}
else{
if (desc == -1){ //Si hi ha algun problema
printf("Error al escoltar\n");
MI_AcabaEscPetiRemConv(sesc);
return 1;
}
else if(desc == TECLAT){ //Client
scanf("%s", adrLUMIrem);
if (strcmp(adrLUMIrem, "/end")!=0) {
res = LUMI_EnviaPeticioLocalitzacio(slumi, adrLUMIloc, adrLUMIrem, IPrem, &port_rem);
//printf("Nanu: %s, amb ip: %s i port %i, intenta parlar amb %s, amb ip: %s i port: %i\n", nickname_l, IPloc, port_loc, nickname_r, IPrem, port_rem);
if (res == 1) { //ha arribat una C
scon = MI_DemanaConv(IPrem, port_rem, IPloc, &port_loc, nickname_l, nickname_r);
if (scon == -1) return 1;
//printf("YES! Nanu: %s, amb ip: %s i port %i, intenta parlar amb %s, amb ip: %s i port: %i\n", nickname_l, IPloc, port_loc, nickname_r, IPrem, port_rem);
connectat = 1;
}
else {
if (res == 0) printf("S'ha rebut un missatge de confirmacio inesperat\n");
else if (res == -1) printf("Error a l'hora d'enviar la peticio de localitzacio\n");
else if (res == -2) printf("Format del missatge de localitzacio enviat incorrecte\n");
else if (res == -3) printf("L'usuari que has indicat no existeix\n");
else if (res == -4) printf("L'usuari que has indicat esta fora de linia\n");
else if (res == -5) printf("Temps d'espera de peticio de localitzacio esgotat\n");
else if (res == -6) printf("Format del missatge de resposta incorrecte\n");
else if (res == -7) printf("L'usuari que has indicat esta ocupat. Prova mes tard\n");
else printf("Error desconegut\n");
}
} else{
MI_AcabaEscPetiRemConv(sesc);
printf("Fins aviat!\n");
return 0;
}
}
else{ //Servidor (sesc)
if ((scon = MI_AcceptaConv(sesc, IPrem, &port_rem, IPloc, &port_loc, nickname_l, nickname_r)) == -1) return 1;
//printf()
printf("Has iniciat una conversa amb %s\n", nickname_r);
connectat = 1;
}
}
}
MI_AcabaEscPetiRemConv(sesc); //Deixem d'escoltar, ja tenim un parell d'usuaris connectats
llistaDesc[1]=scon;
printf("\nConnexio establerta entre %s i %s\n\n", nickname_l, nickname_r);
printf("Dades de l'usuari local: \n\t @MI: %s \n\t IP: %s \n\t Port: %i \n\n", adrLUMIloc, IPloc, port_loc);
printf("Dades de l'usuari remot: \n\t @MI: %s \n\t IP: %s \n\t Port: %i \n\n", adrLUMIrem, IPrem, port_rem);
int canal, fi = 0; //fi ens indica si s'ha de parar la execució del programa o no
char buffer[MAX_MISSATGE]; //Buffer on guardarem les linies que anem rebent
while(!fi){
canal = HaArribatAlgunaCosaEnTemps(llistaDesc, 3, 0); //Obtenim el canal pel qual esta arribant una linia
if(canal == TECLAT){ //Si el canal és teclat significa que nosaltres li volem dir algo al usuari remot
int bytes_llegits = read(TECLAT,buffer,sizeof(buffer)); //Llegim el que li volem enviar i ho fiquem a un buffer
buffer[bytes_llegits-1] = '\0'; //Per protocol convertim aquesta tira entrada en una "String" de C
if (bytes_llegits == -1) perror("Error al entrar per teclat");
if(strcmp(buffer,MARCA_FI) == 0){ //Pot ser que s'hagi indicat que es vol acabar, en aquest cas no s'envia cap linia al usuari remot
MI_AcabaConv(scon); //Tenca la conversa entre els dos
fi = 1;
}
else MI_EnviaLinia(scon,buffer); //Si no és la marca de fi li enviem el que s'ha escrit per teclat
}
else if(canal == scon){ //Si el canal és scon significa que hem rebut una linia de l'usuari remot
int estat_linia; //Variable que ens indica l'estat de la linia que connecta els dos usuaris, no confondre ammb la linia enviada
estat_linia = MI_RepLinia(scon,buffer); //Es rep la linia enviada i es guarda al buffer
if (estat_linia == -1){ //Si hi ha algun error en la recepció
perror("Error: s'ha tancat inesperadament la connexio");
fi = 1;
MI_AcabaConv(scon);
}
else if (estat_linia == -2) { //L'altre ha finalitzat la conversa
fi = 1;
MI_AcabaConv(scon);
printf("L'usuari remot ha finalitzat la connexio\n");
}
else printf("%s: %s\n", nickname_r, buffer); //Si no hi ha cap problema i no s'ha acabat la conversa mostrem la linia rebuda per pantalla
} else if (canal == slumi){
LUMI_RepLiniaDe(slumi, NULL, NULL, resposta, sizeof(resposta));
char adrDESCrem[sizeof(adrLUMIrem)];
LUMI_DescodificarMissatge(resposta[0], resposta, adrDESCrem, NULL, NULL);
if (resposta[0] == 'S') {
LUMI_EnviaResposta(slumi, 'C', adrDESCrem, IPnode, 0); //li passem port 0 per indicar que es un socket UDP "connectat"
}
}
if (canal == -1){ //Si el canal rebut és -1 significa que hi ha algun error
perror("Error desconegut (select)");
MI_AcabaConv(scon);
}
}
printf("Vols parlar amb algu mes? (s/n)\n");
scanf(" %c", &vols_continuar);
usuari_vol_conversa = (vols_continuar == 's');
}
res = LUMI_EnviaPeticioDesregistre(slumi);
if (res == 0) printf("S'ha rebut un missatge de confirmacio inesperat\n");
else if (res == -1) printf("Error a l'hora d'enviar la peticio de desregistre\n");
else if (res == -2) printf("Format del missatge de desregistre enviat incorrecte\n");
else if (res == -3) printf("L'usuari que has indicat no existeix\n");
else if (res == -4) printf("L'usuari que has indicat ja esta desregistrat\n");
else if (res == -5) printf("Temps d'espera de peticio de desregistre esgotat\n");
else if (res == -6) printf("Format del missatge de resposta incorrecte\n");
else printf("Error desconegut\n");
LUMI_Desconnecta(slumi);
printf("Fins aviat!\n");
return 0;
}

7
nodelumi2/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.5)
project(nodelumi2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(SOURCE_FILES MIp2-lumi.h MIp2-lumi.c MIp2-nodelumi.c MIp2-nodelumi.cfg)
add_executable(nodelumi2 ${SOURCE_FILES})

115
nodelumi2/MIp2-agelumi.c Normal file
View File

@ -0,0 +1,115 @@
/**************************************************************************/
/* */
/* P1 - MI amb sockets TCP/IP - Part I */
/* Fitxer p2p.c que implementa la interfície aplicació-usuari de */
/* l'aplicació de MI, sobre la capa d'aplicació de MI (fent crides a la */
/* interfície de la capa MI -fitxers mi.c i mi.h-). */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Inclusió de llibreries, p.e. #include <stdio.h> o #include "meu.h" */
/* Incloem "MIp1v4-mi.h" per poder fer crides a la interfície de MI */
//#include "MIp2-mi.h"
#include "MIp2-lumi.h"
#include "stdio.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
/* Definició de constants, p.e., #define MAX_LINIA 150 */
#define MAX_MISSATGE 300
#define IP_LENGTH 16
#define TECLAT 0
#define MARCA_FI "/end"
int main(int argc,char *argv[])
{
/* Declaració de variables, p.e., int n; */
int sesc, scon, slumi; //socket descriptor dels sockets
int port=0, port_loc, port_rem; //port: farà de port local o remot segons la situació. Les variables port_loc i port_rem son per claretat de codi.
char IPloc[IP_LENGTH], IPrem[IP_LENGTH], IPnode[IP_LENGTH]; //IPs local i remota i del node
char adrLUMIloc[MAX_LEN_DOMINI+MAX_USER_NICK+1], adrLUMIrem[MAX_LEN_DOMINI+MAX_USER_NICK+1];
char nickname_l[MAX_MISSATGE], nickname_r[MAX_MISSATGE]; //Nicknames local i remot
//char vols_continuar; //Eleccio de l'usuari
int fitxer_log;
int usuari_vol_conversa=1, connectat = 0, res; //Boolea per saber si l'usuari vol seguir parlant
/* Expressions, estructures de control, crides a funcions, etc. */
printf("Entra la teva @MI: ");
scanf("%s", adrLUMIloc);
//strcpy(adrLUMIloc,"Enric@localhost");
if ((slumi = LUMI_InicialitzarAgent("0.0.0.0",0, &fitxer_log, adrLUMIloc, IPnode)) < 0){
//Apagar tot
close(slumi);
//close(sesc);
return 1;
}
//printf("Landmark");
res = LUMI_EnviaPeticioRegistre(slumi, adrLUMIloc);
if (res == -5) printf("El node esta 7at");
else if(res < 0){
close(slumi);
printf("FAIL%i\n",res);
//close(sesc);
return 1;
} else printf("Registrat correctament\n");
if (strcmp(adrLUMIloc,"Enric@localhost") != 0){
int llista[] = {slumi};
HaArribatAlgunaCosaEnTemps(llista, 1, 0);
char resposta[MAX_MISSATGE_PLUMI];
LUMI_RepLiniaDe(slumi, NULL, NULL, resposta, sizeof(resposta));
LUMI_DescodificarMissatge(resposta[0], resposta, adrLUMIrem, NULL, NULL);
printf("%s ens vol localitzar\n", adrLUMIrem);
int res2 = LUMI_EnviaRespostaServeiLocalitzacio(slumi, adrLUMIrem, "10.0.0.13", 1337);
printf("Localitzacio: %i\n", res2);
}
else{
//scanf("%s", adrLUMIrem);
strcpy(adrLUMIrem,"Marc@localhost");
res = LUMI_EnviaPeticioLocalitzacio(slumi, adrLUMIloc, adrLUMIrem, IPrem, &port_rem, adrLUMIrem);
printf("Hola!\n");
if (res == -5) printf("El node esta 7at");
else if(res < 0){
close(slumi);
//close(sesc);
return 1;
}
else printf("Localitzat correctament\n");
}
res = LUMI_EnviaPeticioDesregistre(slumi);
if (res == -5) printf("El node esta 7at");
else if(res < 0){
close(slumi);
//close(sesc);
return 1;
}
else printf("Desregistrat correctament\n");
/*Localitzar();
Desregistrar();*/
return 0;
}

728
nodelumi2/MIp2-lumi.c Executable file
View File

@ -0,0 +1,728 @@
/**************************************************************************/
/* */
/* P2 - MI amb sockets TCP/IP - Part II */
/* Fitxer lumi.c que implementa la capa d'aplicació de LUMI, sobre la */
/* de transport UDP (fent crides a la interfície de la capa UDP */
/* -sockets-). */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Inclusió de llibreries, p.e. #include <sys/types.h> o #include "meu.h" */
/* (si les funcions externes es cridessin entre elles, faria falta fer */
/* un #include "MIp2-lumi.h") */
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
#include <netdb.h>
#include "MIp2-lumi.h"
/* Definició de constants, p.e., #define MAX_LINIA 150 */
#define RETRANSMISSIONS 10
#define TIMEOUT 100
/* Declaració de funcions internes que es fan servir en aquest fitxer */
/* (les seves definicions es troben més avall) per així fer-les conegudes */
/* des d'aqui fins al final de fitxer. */
/* Com a mínim heu de fer les següents funcions internes: */
int UDP_CreaSock(const char *IPloc, int portUDPloc);
int UDP_EnviaA(int Sck, const char *IPrem, int portUDPrem, const char *SeqBytes, int LongSeqBytes);
int UDP_RepDe(int Sck, char *IPrem, int *portUDPrem, char *SeqBytes, int LongSeqBytes);
int UDP_TancaSock(int Sck);
int UDP_TrobaAdrSockLoc(int Sck, char *IPloc, int *portUDPloc);
int UDP_DemanaConnexio(int Sck, const char *IPrem, int portUDPrem);
int UDP_Envia(int Sck, const char *SeqBytes, int LongSeqBytes);
int UDP_Rep(int Sck, char *SeqBytes, int LongSeqBytes);
int UDP_TrobaAdrSockRem(int Sck, char *IPrem, int *portUDPrem);
///int HaArribatAlgunaCosaEnTemps(const int *LlistaSck, int LongLlistaSck, int Temps);
///int ResolDNSaIP(const char *NomDNS, char *IP);
int Log_CreaFitx(const char *NomFitxLog);
int Log_Escriu(int FitxLog, const char *MissLog);
int Log_TancaFitx(int FitxLog);
int LUMI_DescodificarSockTCPMissatgeC(const char * Missatge, char * IP, int * portTCP, char * adreca);
/* Definicio de funcions EXTERNES, és a dir, d'aquelles que en altres */
/* fitxers externs es faran servir. */
/* En termes de capes de l'aplicació, aquest conjunt de funcions externes */
/* formen la interfície de la capa LUMI. */
/* Les funcions externes les heu de dissenyar vosaltres... */
/* Definicio de funcions INTERNES, és a dir, d'aquelles que es faran */
/* servir només en aquest mateix fitxer. */
/* Crea un socket UDP a l@IP “IPloc” i #port UDP “portUDPloc” */
/* (si “IPloc” és “0.0.0.0” i/o “portUDPloc” és 0 es fa/farà una */
/* assignació implícita de l@IP i/o del #port UDP, respectivament). */
/* "IPloc" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* Retorna -1 si hi ha error; lidentificador del socket creat si tot */
/* va bé. */
int UDP_CreaSock(const char *IPloc, int portUDPloc)
{
int sockdesc;
if ((sockdesc = socket(AF_INET,SOCK_DGRAM,0)) == -1){
LUMI_MostraError("Error creació socket");
return -1;
}
else{
struct sockaddr_in adr;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPloc);
adr.sin_port = htons(portUDPloc);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
if (bind(sockdesc,(struct sockaddr*)&adr,sizeof(adr))==-1){
LUMI_MostraError("Error bind");
return -1;
}
}
return sockdesc;
}
/* Envia a través del socket UDP didentificador “Sck” la seqüència de */
/* bytes escrita a “SeqBytes” (de longitud “LongSeqBytes” bytes) cap al */
/* socket remot que té @IP “IPrem” i #port UDP “portUDPrem”. */
/* "IPrem" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* "SeqBytes" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud >= LongSeqBytes bytes */
/* Retorna -1 si hi ha error; el nombre de bytes enviats si tot va bé. */
int UDP_EnviaA(int Sck, const char *IPrem, int portUDPrem, const char *SeqBytes, int LongSeqBytes)
{
struct sockaddr_in adrrem;
adrrem.sin_family=AF_INET;
adrrem.sin_port=htons(portUDPrem);
adrrem.sin_addr.s_addr= inet_addr(IPrem);
int i;
for(i=0;i<8;i++){adrrem.sin_zero[i]='\0';}
int bytes_llegits;
if((bytes_llegits=sendto(Sck,SeqBytes,LongSeqBytes,0,(struct sockaddr*)&adrrem,sizeof(adrrem)))==-1)
{
perror("Error en sendto");
close(Sck);
return(-1);
}
return bytes_llegits;
}
/* Rep a través del socket UDP didentificador “Sck” una seqüència de */
/* bytes que prové d'un socket remot i lescriu a “SeqBytes*” (que té */
/* una longitud de “LongSeqBytes” bytes). */
/* Omple "IPrem*" i "portUDPrem*" amb respectivament, l'@IP i el #port */
/* UDP del socket remot. */
/* "IPrem*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* "SeqBytes*" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud <= LongSeqBytes bytes */
/* Retorna -1 si hi ha error; el nombre de bytes rebuts si tot va bé. */
int UDP_RepDe(int Sck, char *IPrem, int *portUDPrem, char *SeqBytes, int LongSeqBytes)
{
struct sockaddr_in adrrem;
socklen_t ladrrem = sizeof(adrrem);
int bytes_llegits;
if((bytes_llegits=recvfrom(Sck,SeqBytes,LongSeqBytes,0,(struct sockaddr*)&adrrem,&ladrrem))==-1)
{
perror("Error recvfrom\n");
close(Sck);
return -1;
}
strcpy(IPrem, inet_ntoa(adrrem.sin_addr));
*portUDPrem = ntohs(adrrem.sin_port);
return bytes_llegits;
}
/* Sallibera (sesborra) el socket UDP didentificador “Sck”. */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int UDP_TancaSock(int Sck)
{
return close(Sck);
}
/* Donat el socket UDP didentificador “Sck”, troba ladreça daquest */
/* socket, omplint “IPloc*” i “portUDPloc*” amb respectivament, la seva */
/* @IP i #port UDP. */
/* "IPloc*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0') */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int UDP_TrobaAdrSockLoc(int Sck, char *IPloc, int *portUDPloc)
{
struct sockaddr_in sin;
socklen_t slen;
slen = sizeof(sin);
if(getsockname(Sck, (struct sockaddr *)&sin, &slen)){
LUMI_MostraError("Error al trobar la direccio local");
return -1;
}
*portUDPloc = ntohs(sin.sin_port);
strcpy(IPloc, inet_ntoa(sin.sin_addr));
return 1;
}
/* El socket UDP didentificador “Sck” es connecta al socket UDP d@IP */
/* “IPrem” i #port UDP “portUDPrem” (si tot va bé es diu que el socket */
/* “Sck” passa a lestat “connectat” o establert established ). */
/* Recordeu que a UDP no hi ha connexions com a TCP, i que això només */
/* vol dir que es guarda localment ladreça “remota” i així no cal */
/* especificar-la cada cop per enviar i rebre. Llavors quan un socket */
/* UDP està “connectat” es pot fer servir UDP_Envia() i UDP_Rep() (a més */
/* de les anteriors UDP_EnviaA() i UDP_RepDe()) i UDP_TrobaAdrSockRem()). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int UDP_DemanaConnexio(int Sck, const char *IPrem, int portUDPrem)
{
struct sockaddr_in adr;
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(IPrem);
adr.sin_port = htons(portUDPrem);
int i;
for(i=0;i<8;i++){adr.sin_zero[i]='0';}
if((connect(Sck,(struct sockaddr*)&adr,sizeof(adr)))==-1){
char buff[100];
snprintf(buff, sizeof(buff), "Error: no s'ha pogut connectar amb %s", IPrem);
LUMI_MostraError(buff);
return -1;
}
return 0;
}
/* Envia a través del socket UDP “connectat” didentificador “Sck” la */
/* seqüència de bytes escrita a “SeqBytes” (de longitud “LongSeqBytes” */
/* bytes) cap al socket UDP remot amb qui està connectat. */
/* "SeqBytes" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud >= LongSeqBytes bytes. */
/* Retorna -1 si hi ha error; el nombre de bytes enviats si tot va bé. */
int UDP_Envia(int Sck, const char *SeqBytes, int LongSeqBytes)
{
return send(Sck,SeqBytes,LongSeqBytes,0);
}
/* Rep a través del socket UDP “connectat” didentificador “Sck” una */
/* seqüència de bytes que prové del socket remot amb qui està connectat, */
/* i lescriu a “SeqBytes*” (que té una longitud de “LongSeqBytes” bytes).*/
/* "SeqBytes*" és un vector de chars qualsevol (recordeu que en C, un */
/* char és un enter de 8 bits) d'una longitud <= LongSeqBytes bytes. */
/* Retorna -1 si hi ha error; el nombre de bytes rebuts si tot va bé. */
int UDP_Rep(int Sck, char *SeqBytes, int LongSeqBytes)
{
return recv(Sck,SeqBytes,LongSeqBytes,0);
}
/* Donat el socket UDP “connectat” didentificador “Sck”, troba ladreça */
/* del socket remot amb qui està connectat, omplint “IPrem*” i */
/* “portUDPrem*” amb respectivament, la seva @IP i #port UDP. */
/* "IPrem*" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud màxima de 16 chars (incloent '\0'). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int UDP_TrobaAdrSockRem(int Sck, char *IPrem, int *portUDPrem)
{
struct sockaddr_in adr;
socklen_t long_adr = sizeof(adr);
int res;
if ( (res = getpeername(Sck, (struct sockaddr*)&adr, &long_adr)) == -1) {
LUMI_MostraError("Error al trobar la direccio remota");
return -1;
}
strcpy(IPrem,inet_ntoa(adr.sin_addr));
*portUDPrem = ntohs(adr.sin_port);
return res;
}
/* Examina simultàniament durant "Temps" (en [ms] els sockets (poden ser */
/* TCP, UDP i stdin) amb identificadors en la llista “LlistaSck” (de */
/* longitud “LongLlistaSck” sockets) per saber si hi ha arribat alguna */
/* cosa per ser llegida. Si Temps és -1, s'espera indefinidament fins que */
/* arribi alguna cosa. */
/* "LlistaSck" és un vector d'enters d'una longitud >= LongLlistaSck */
/* Retorna -1 si hi ha error; retorna -2 si passa "Temps" sense que */
/* arribi res; si arriba alguna cosa per algun dels sockets, retorna */
/* lidentificador daquest socket. */
int HaArribatAlgunaCosaEnTemps(const int *LlistaSck, int LongLlistaSck, int Temps)
{
struct timeval timeout;
timeout.tv_sec = Temps/1000;
timeout.tv_usec = (Temps%1000)*1000; //estructura per definir un timeout al select
fd_set set;
FD_ZERO(&set);
int i = 0;
while (i<LongLlistaSck){
FD_SET(LlistaSck[i],&set);
i++;
}
int smax = 0;
i=0;
while(i<LongLlistaSck){
if (smax<LlistaSck[i]) smax = LlistaSck[i];
i++;
}
smax++;
if (Temps > 0){
int res;
if ((res = select(smax,&set,NULL,NULL,&timeout)) == -1){
LUMI_MostraError("Error a la espera d'arribar alguna cosa");
return -1;
}
if(res == 0) return 0;
}
else if (select(smax,&set,NULL,NULL,NULL) == -1){
LUMI_MostraError("Error a la espera d'arribar alguna cosa");
return -1;
}
int ifd=0;
while( ifd < LongLlistaSck && !FD_ISSET(LlistaSck[ifd],&set) ) ifd++;
return LlistaSck[ifd];
}
/* Donat el nom DNS "NomDNS" obté la corresponent @IP i l'escriu a "IP*" */
/* "NomDNS" és un "string" de C (vector de chars imprimibles acabat en */
/* '\0') d'una longitud qualsevol, i "IP*" és un "string" de C (vector de */
/* chars imprimibles acabat en '\0') d'una longitud màxima de 16 chars */
/* (incloent '\0'). */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé */
int ResolDNSaIP(const char *NomDNS, char *IP)
{
struct addrinfo hints, *infoptr;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // AF_INET perquè només volem adreces IPv4
int result = getaddrinfo(NomDNS, NULL, &hints, &infoptr);
if (result != 0) {
fprintf(stderr, "Error a getaddrinfo\n%s\n",gai_strerror(result));
return(-1);
}
struct addrinfo *p;
char host[256];
p = infoptr;
result = getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if (result != 0) {
fprintf(stderr, "Error a getnameinfo\n");
return(-1);
}
strcpy(IP, host);
freeaddrinfo(infoptr);
return 0;
}
/* Crea un fitxer de "log" de nom "NomFitxLog". */
/* "NomFitxLog" és un "string" de C (vector de chars imprimibles acabat */
/* en '\0') d'una longitud qualsevol. */
/* Retorna -1 si hi ha error; l'identificador del fitxer creat si tot va */
/* bé. */
int Log_CreaFitx(const char *NomFitxLog)
{
int filedesc = open(NomFitxLog, O_APPEND|O_CREAT, 0666);
if (filedesc < 0){
LUMI_MostraError("Error al crear el fitxer Log");
return -1;
}
return filedesc;
}
/* Escriu al fitxer de "log" d'identificador "FitxLog" el missatge de */
/* "log" "MissLog". */
/* "MissLog" és un "string" de C (vector de chars imprimibles acabat */
/* en '\0') d'una longitud qualsevol. */
/* Retorna -1 si hi ha error; el nombre de caràcters del missatge de */
/* "log" (sense el '\0') si tot va bé */
int Log_Escriu(int FitxLog, const char *MissLog)
{
int lMiss = strlen(MissLog);
char buff[lMiss];
strcpy(buff,MissLog);
//buff[lMiss-1] = '\n';
/*int res = write(FitxLog,MissLog,strlen(MissLog)-1);
if (res < 0) return res;*/
return write(FitxLog,buff,sizeof(buff));
}
/* Tanca el fitxer de "log" d'identificador "FitxLog". */
/* Retorna -1 si hi ha error; un valor positiu qualsevol si tot va bé. */
int Log_TancaFitx(int FitxLog)
{
return close(FitxLog);
}
void LUMI_MostraError(const char *text)
{
fprintf(stderr, "%s\n", text);
}
/* Si ho creieu convenient, feu altres funcions... */
int LUMI_InicialitzarNode(const char * fitxer_log){
//printf("%s\n",fitxer_log);
LUMI_Fitxer_Log = Log_CreaFitx(fitxer_log); //el nom del fitxer ha de portar el nom del domini
return UDP_CreaSock("0.0.0.0",UDP_PORT);
}
int LUMI_InicialitzarAgent(const char * IP, int portUDP, int * fitxer_log, const char * adrLUMI, char * IPnode){
int res = UDP_CreaSock(IP,portUDP);
if (res < 0 ) return res;
char nickname[MAX_USER_NICK], domini[MAX_LEN_DOMINI];
LUMI_DescodificarAdreca(adrLUMI, nickname, domini);
//printf("nick: %s, domini: %s",nickname,domini);
if (ResolDNSaIP(domini, IPnode) < 0) return -1;
if (UDP_DemanaConnexio(res, IPnode, UDP_PORT) < 0) return -1;
char nom_fitxer[MAX_NOM_FITXER];
LUMI_ResolNomFitxerLog('A', nom_fitxer, adrLUMI);
if ( (*fitxer_log = Log_CreaFitx(nom_fitxer)) < 0 ) return -2;
return res;
}
int LUMI_ResolNomFitxerLog(char tipus, char * fitxer_log, const char * buffer){
if (tipus == 'A' ) strcpy(fitxer_log, NOM_FITXER_AGENT);
else if (tipus == 'N') strcpy(fitxer_log, NOM_FITXER_NODE);
else return 1;
strcat(fitxer_log, buffer);
strcat(fitxer_log, EXT_FITXER_LOG);
return 0;
}
int LUMI_EnviaFiable(int Sck, const char * Missatge, char * resposta, int timeout){
int intents = 0, enviat = 0, res, retorn;
int llist[] = {Sck};
while(!enviat && intents<INTENTS){
UDP_Envia(Sck,Missatge,strlen(Missatge));
res = HaArribatAlgunaCosaEnTemps(llist,1,timeout);
if (res < 0){
LUMI_MostraError("Error al esperar EnviaFiable");
return -1;
}
else if (res > 0 ){ //Si hem rebut algo, comprovem si es una A (resposta)
char buff[MAX_MISSATGE_PLUMI];
int longitud = UDP_Rep(Sck, buff, sizeof(buff));
buff[longitud]='\0';
if(LUMI_ComprovarFormat(buff) != 0) return -6;
if (buff[0] == 'A'){
switch(buff[1]){
case 'K':
retorn = 0;
break;
case 'I':
retorn = -2;
break;
case 'N':
retorn = -3;
break;
case 'C':
retorn = -7;
break;
default:
retorn = -4;
break;
}
enviat = 1; //Si es una resposta, vol dir que el destinatari ha rebut be el paquet
} else if (buff[0]== 'C') {retorn = 1; enviat = 1;}
if (resposta != NULL) strcpy(resposta, buff);
}//else printf("%s. Intent %i\n", "TIMEOUT EXPIRED", intents);//LUMI_MostraError("TIMEOUT EXPIRED\n");
intents++;
}
if (enviat == 0){
/*Log_Escriu(LUMI_Fitxer_Log,"Ha fallat l'enviament del seguent missatge: \n\t");
Log_Escriu(LUMI_Fitxer_Log,Missatge);
Log_Escriu(LUMI_Fitxer_Log,"\n\n");*/
return -5;
}
else{
/*Log_Escriu(LUMI_Fitxer_Log,"S'ha enviat correctament el seguent missatge: \n\t");
Log_Escriu(LUMI_Fitxer_Log,Missatge);
Log_Escriu(LUMI_Fitxer_Log,"\n\n");*/
return retorn;
}
}
int LUMI_EnviaLiniaA(int Sck, const char * IP, int portUDPrem, const char * buffer){
return UDP_EnviaA(Sck, IP, portUDPrem, buffer, strlen(buffer));
}
int LUMI_EnviaPeticioRegistre(int Sck, char * adrLUMI){
char buffer[MAX_MISSATGE_PLUMI+1];
sprintf(buffer,"R%s",adrLUMI);
return LUMI_EnviaFiable(Sck, buffer, NULL, TIMEOUT);
}
int LUMI_EnviaPeticioDesregistre(int Sck){
return LUMI_EnviaFiable(Sck, "D", NULL, TIMEOUT);
}
int LUMI_EnviaResposta(int Sck, char tipus, const char * adrLUMI, const char * IP, int portUDPrem){
char buffer[MAX_MISSATGE_PLUMI+1];
if(adrLUMI==NULL) sprintf(buffer,"A%c",tipus);
else sprintf(buffer,"A%c%s",tipus, adrLUMI);
if(portUDPrem==0) return UDP_Envia(Sck, buffer, strlen(buffer));
else return UDP_EnviaA(Sck, IP, portUDPrem, buffer, strlen(buffer));
}
int LUMI_EnviaPeticioLocalitzacio(int Sck, const char * adrLUMIloc, const char * adrLUMIrem, char * IPlocalitzat, int * portTCP){
char buffer[MAX_MISSATGE_PLUMI+1];
sprintf(buffer,"L%s#%s", adrLUMIrem, adrLUMIloc);
char resposta[MAX_MISSATGE_PLUMI+1];
int res = LUMI_EnviaFiable(Sck, buffer, resposta, TIMEOUT*2);
//printf("%s\n", resposta);
if (res <= 0) return res;
else if (res == 1){
LUMI_DescodificarSockTCPMissatgeC(resposta,IPlocalitzat,portTCP, NULL);
return res;
}
}
int LUMI_EnviaPeticioServeiLocalitzacio(int Sck, const char * adrLUMI, const char * IP, int portUDPrem){
char buffer[MAX_MISSATGE_PLUMI+1];
sprintf(buffer,"S%s",adrLUMI);
return UDP_EnviaA(Sck, IP, portUDPrem, buffer, strlen(buffer));
}
int LUMI_EnviaRespostaServeiLocalitzacio(int Sck, const char * adrLUMI, const char * IP, int portTCPrem){
char buffer[MAX_MISSATGE_PLUMI+1];
sprintf(buffer,"C%s#%i#%s",IP, portTCPrem, adrLUMI);
//printf("%s\n", buffer);
return UDP_Envia(Sck, buffer, strlen(buffer));
}
int LUMI_DescodificarAdreca(const char * adr, char * nickname, char * domini){
int i=0;
while (adr[i]!='@') i++;
if (domini != NULL) strcpy(domini, adr+i+1);
if (nickname != NULL){
strncpy(nickname, adr, i);
nickname[i]='\0';
}
return 0;
}
int LUMI_DescodificarMissatge(char tipus, const char * Missatge, char * adreca, char * domini, char * nom_usuari){
if (tipus == 'R'){
strcpy(adreca,Missatge+1);
LUMI_DescodificarAdreca(adreca, nom_usuari, domini);
}
else if (tipus == 'L'){
char buffer[MAX_USER_NICK+MAX_LEN_DOMINI+2];
int i=1;
while (Missatge[i]!='#') i++;
strncpy(buffer, Missatge+1, i-1);
buffer[i-1]='\0';
LUMI_DescodificarAdreca(buffer,nom_usuari,domini);
strcpy(adreca, Missatge+i+1);
}
else if (tipus == 'A'){
int longitud = strlen(Missatge);
if (longitud > 2) {
strcpy(adreca,Missatge+2);
LUMI_DescodificarAdreca(adreca, nom_usuari, domini);
}
}
else if (tipus == 'S'){
strcpy(adreca,Missatge+1);
LUMI_DescodificarAdreca(adreca, nom_usuari, domini);
}
else if(tipus == 'C'){
int i, j=1;
for(i = 1; i < 3; i++){ //ens saltem els dos primers # i ens posicionem sobre el tercer
while (Missatge[j]!='#') j++;
j++;
}
strcpy(adreca,Missatge+j);
//printf("%s\n", adreca);
LUMI_DescodificarAdreca(adreca, nom_usuari, domini);
}
else if (tipus == 'D') return 0;
else return -1;
return 0;
}
int LUMI_DescodificarSockTCPMissatgeC(const char * Missatge, char * IP, int * portTCP, char * adreca){
int i=1, j;
char buffer[6];
while (Missatge[i]!='#') i++;
strncpy(IP,Missatge+1,i-1); //aixo esta mal
IP[i-1]='\0';
j=i+1;
while (Missatge[j]!='#') j++;
strncpy(buffer,Missatge+i+1,j-i-1);
*portTCP=atoi(buffer);
if (adreca != NULL) strcpy(adreca, Missatge+j+1);
return 0;
}
int comprovarIP(const char * IP){ //aka "la fàbrica de bugs"
int i=0, mida=strlen(IP), punts=0, old=-1, temp;
char buff[16];
char c;
while(i<mida){
c=IP[i];
if(c!='.' && !(c<='9' && c>='0')) return 2;
i++;
}
i=0;
while(i<mida){
while(IP[i]!='.' && i<mida) i++;
strncpy(buff, IP+old+1, i-old-1);
buff[i-old-1]='\0';
temp=atoi(buff);
if(temp<=0 || temp>255) return 1;
old=i;
i++;
punts++;
}
if (punts != 4 || IP[mida-1]=='.') return -1;
return 0;
}
int validarAdreca(const char * adreca, int longAdr){
int i = 0;
while( i < longAdr && adreca[i]!='#' && adreca[i]!='@') i++;
if(i == longAdr || adreca[i]=='#') return 1;
else return 0;
}
int LUMI_ComprovarFormat(const char * buffer){
int mida=strlen(buffer), i=1, j;
char tipus = buffer[0];
switch(tipus){
case 'R':
case 'S':
if (mida == 1) return 1;
else{
if (validarAdreca(buffer+1,mida-1) == 1) return 1;
}
break;
case 'D':
if (mida > 1) return 1;
break;
case 'L':
if(mida == 1) return 1;
while (buffer[i]!='@' && buffer[i]!='#' && i<mida) i++;//busquem la primera @
if(buffer[i]=='#' && i == mida) return 1; //si no la trobem abans que un # o que el fi del missatge
while (buffer[i]!='#' && i<mida) i++;//busquem el #
if (i == mida) return 1;//si no el trobem abans que el fi del missatge
while (buffer[i]!='@' && i<mida) i++; //busquem la segona @
if(i == mida) return 1; //si no la trobem
break;
case 'A':
if(mida>2){
while (buffer[i]!='@' && i<mida) i++;
if(i == mida) return 1;
}
else if (mida == 2){
if (buffer[1] != 'K' && buffer[1] != 'I' && buffer[1] != 'N') return 1;
}
else return 1;
break;
case 'C':
if(mida == 1) return 1;
while (buffer[i]!='#' && i<mida) i++;// busuquem el primer #
if(i == mida) return 1;
if(i > IP_LENGTH || i-1 <7 ) return 1;
/*C222.222.222.222#
01234567891111111
0123456*/
char ip[IP_LENGTH];
strncpy(ip, buffer+1, i-1);
ip[i-1] = '\0';
//if(comprovarIP(ip) == 1) return 1; //millor que no estigues implementada
j= i+1;
while (buffer[j]!='#' && j<mida) j++;//busquem la segona marca #
char port[6];
strncpy(port,buffer+i+1,j-i-1);
port[j-i-1]='\0';
int res=atoi(port);
if(res == 0 || res > MAX_PORT) return 1; //comprobem que el port es un nuumero compres entre 0 i 65535
if(validarAdreca(buffer+j+1,mida-j) == 1) return 1;
break;
default:
return 1;
break;
}
return 0;
}
int LUMI_RepLiniaDe(int Sck, char * IPrem, int * portUDP, char * buffer, int mida_buffer){
int res;
if (IPrem != NULL && portUDP != NULL) res = UDP_RepDe(Sck, IPrem, portUDP, buffer, mida_buffer);
else res = UDP_Rep(Sck,buffer,mida_buffer);
if (res <= 0) return res;
buffer[res]='\0';
if(LUMI_ComprovarFormat(buffer) == 1){
LUMI_EnviaResposta(Sck,'I', NULL, IPrem, *portUDP);
return -2;
}
return res;
}
int LUMI_EscriureFitxerLog(int fitxer, const char * linia){
return 0;
}
int LUMI_Desconnecta(int Sck){
close(Sck);
}

73
nodelumi2/MIp2-lumi.h Executable file
View File

@ -0,0 +1,73 @@
/**************************************************************************/
/* */
/* P2 - MI amb sockets TCP/IP - Part II */
/* Fitxer capçalera de lumi.c */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
#define UDP_PORT 7189
#define IP_LENGTH 16
#define MAX_USER_NICK 20
#define MAX_MISSATGE_PLUMI 150
#define MAX_LEN_DOMINI 100
#define MAX_PORT 65535
#define INTENTS 5
#define MAX_NOM_FITXER 100
#define NOM_FITXER_NODE "MIp2-nodelumi-"
#define NOM_FITXER_CONFIG "MIp2-nodelumi.cfg"
#define NOM_FITXER_AGENT "MIp2-agelumi-"
#define EXT_FITXER_LOG ".log"
/* Declaració de funcions externes de lumi.c, és a dir, d'aquelles que es */
/* faran servir en un altre fitxer extern, p.e., MIp2-p2p.c, */
/* MIp2-nodelumi.c, o MIp2-agelumic.c. El fitxer extern farà un #include */
/* del fitxer .h a l'inici, i així les funcions seran conegudes en ell. */
/* En termes de capes de l'aplicació, aquest conjunt de funcions externes */
/* formen la interfície de la capa LUMI. */
/* Les funcions externes les heu de dissenyar vosaltres... */
//int LUMI_FuncioExterna(arg1, arg2...);
struct usuari;
int LUMI_Fitxer_Log;
void LUMI_MostraError(const char *text);
int LUMI_ComprovarFormat(const char * buffer);
int LUMI_DescodificarAdreca(const char * adr, char * nickname, char * domini);
int LUMI_ResolNomFitxerLog(char tipus, char * fitxer_log, const char * buffer);
int LUMI_RepLiniaDe(int Sck, char * IPrem, int * portUDP, char * buffer, int mida_buffer);
int LUMI_EnviaFiable(int Sck, const char * Missatge, char * resposta, int timeout);
int LUMI_EnviaLiniaA(int Sck, const char * IP, int portUDPrem, const char * buffer);
int LUMI_EnviaPeticioRegistre(int Sck, char * adrLUMI);
int LUMI_EnviaPeticioDesregistre(int Sck);
int LUMI_EnviaResposta(int Sck, char tipus, const char * adrLUMI, const char * IP, int portUDPrem);
int LUMI_EnviaPeticioLocalitzacio(int Sck, const char * adrLUMIloc, const char * adrLUMIrem, char * IPlocalitzat, int * portTCP);
int LUMI_EnviaPeticioServeiLocalitzacio(int Sck, const char * adrLUMI, const char * IP, int portUDPrem);
int LUMI_EnviaRespostaServeiLocalitzacio(int Sck, const char * adrLUMI, const char * IP, int portTCPrem);
int LUMI_DescodificarMissatge(char tipus, const char * Missatge, char * adreca, char * domini, char * nom_usuari);
int LUMI_InicialitzarNode(const char * fitxer_log);
int LUMI_InicialitzarAgent(const char * IP, int portUDP, int * fitxer_log, const char * adrLUMI, char * IPnode);
int HaArribatAlgunaCosaEnTemps(const int *LlistaSck, int LongLlistaSck, int Temps);
int ResolDNSaIP(const char *NomDNS, char *IP);
int LUMI_Desconnecta(int Sck);

304
nodelumi2/MIp2-nodelumi.c Normal file
View File

@ -0,0 +1,304 @@
/**************************************************************************/
/* */
/* P2 - MI amb sockets TCP/IP - Part II */
/* Fitxer nodelumi.c que implementa la interfície aplicació-administrador */
/* d'un node de LUMI, sobre la capa d'aplicació de LUMI (fent crides a la */
/* interfície de la capa LUMI -fitxers lumi.c i lumi.h-). */
/* */
/* Autors: Marc Cané Salamià, Enric Rodríguez Galán */
/* */
/**************************************************************************/
/* Inclusió de llibreries, p.e. #include <stdio.h> o #include "meu.h" */
/* Incloem "MIp2-lumi.h" per poder fer crides a la interfície de LUMI */
#include "MIp2-lumi.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
/* Definició de constants, p.e., #define MAX_LINIA 150 */
struct usuari{
char nom[MAX_USER_NICK];
char IP[IP_LENGTH];
int UDP_port;
};
int ObrirFitxLectura(const char *NomFitx)
{
int filedesc = open(NomFitx, O_RDONLY);
if (filedesc < 0){
LUMI_MostraError("Error al obrir el fitxer de configuracio");
return -1;
}
return filedesc;
}
//Pre: buff apunta a un buffer del màxim de caràcters que pot tenir una línia
//Post: retorna 1 si no s'ha arribat a la marca de fi de fitxer, 0 altrament
int LlegirLinia(int fitxer, char * buff){
char c=0;
int byte_llegit=1, i=0;
while(byte_llegit!=0 && c!='\n'){
byte_llegit=read(fitxer,&c,1);
buff[i]=c;
i++;
}
buff[i-1]='\0';
return byte_llegit;
}
char DOMINI[MAX_LEN_DOMINI];
void InicialitzarTaulaUsuaris(struct usuari ** taula_usuaris, int n){
*taula_usuaris = (struct usuari *) malloc(sizeof(struct usuari)*n);
}
int CercarUsuariPerNom(struct usuari * taula_usuaris, const char * NomUsuari, int n_usuaris){
/*int trobat = 0, mig, esq=0 , dret = n_usuaris-1 , comparacio;
while(trobat == 0 && esq<=dret){
mig = (dret + esq) / 2;
comparacio = strcmp(taula_usuaris[mig].nom, NomUsuari);
if (comparacio == 0) trobat = 1;
else{
if (comparacio < 0) esq=mig+1;
else dret=mig-1;
}
}
if (trobat == 1) return mig;
else return (-1)*mig;*/
int i=0, trobat=0;
while(i<n_usuaris && !trobat){
if(strcmp(taula_usuaris[i].nom, NomUsuari)==0)
trobat=1;
else i++;
}
return trobat?i:-1*i;
}
int CercarUsuariPerIPiPort(struct usuari * taula_usuaris, const char * IP, int port, int n_usuaris){
int trobat = 0, i = 0;
while (i<n_usuaris && !trobat) {
if ((strcmp(taula_usuaris[i].IP, IP) == 0) && (taula_usuaris[i].UDP_port == port)) trobat = 1;
else i++;
}
return trobat?i:-1*i;
}
void intercanviar(struct usuari * taula_usuaris, int i, int j){
struct usuari aux = taula_usuaris[i];
taula_usuaris[i] = taula_usuaris[j];
taula_usuaris[j] = aux;
}
//n _usuaris < max_usuaris sempre
int DonardAltaUsuari(struct usuari * taula_usuaris, const char * NomUsuari, int n_usuaris, int max_usuaris){
if (n_usuaris == max_usuaris) return -1;
int posicio = CercarUsuariPerNom(taula_usuaris, NomUsuari, n_usuaris);
if (posicio > 0) {
//LUMI_MostraError("Error: l'usuari %s ja esta donat d'alta", NomUsuari);
return -1;
}
else{
/*int i;
posicio*=-1;
for(i = n_usuaris-1; i>posicio; i--) intercanviar(taula_usuaris,i,i-1); //potser aixo peta*/
posicio = n_usuaris;
strcpy(taula_usuaris[posicio].nom, NomUsuari);
taula_usuaris[posicio].UDP_port=-1;
}
return 1;
}
int LlegirTaulaDesdeFitxer(const char * file_name, struct usuari ** taula_usuaris){
int fitxer = ObrirFitxLectura(file_name);
if (fitxer == -1) return -1;
char buff[100];
int byte_llegit, total_usuaris=0, alta_usuaris=0;
LlegirLinia(fitxer,buff); //llegim el nom del domini
strcpy(DOMINI,buff);
LlegirLinia(fitxer,buff); //llegim el nombre d'usuaris del domini
total_usuaris=atoi(buff);
InicialitzarTaulaUsuaris(taula_usuaris, total_usuaris);
byte_llegit = LlegirLinia(fitxer,buff); //legir primer usuari
//printf("%i", (*taula_usuaris)[0].UDP_port);
while(byte_llegit!=0 && alta_usuaris<total_usuaris){
if ( DonardAltaUsuari(*taula_usuaris,buff,alta_usuaris,total_usuaris) == -1){
//error l'usuari ja exisita, s'ha de ficar al fitxer log
} else alta_usuaris++;
byte_llegit = LlegirLinia(fitxer,buff);
}
return alta_usuaris;
}
int desregistrarUsuari(struct usuari * taula_usuaris, int usuari){
taula_usuaris[usuari].UDP_port = -1;
return 0;
}
int registrarUsuari(struct usuari * taula_usuaris, int usuari, const char * IP, int portUDP){
strcpy(taula_usuaris[usuari].IP,IP);
taula_usuaris[usuari].UDP_port = portUDP;
return 0;
}
int main(int argc,char *argv[])
{
/* Declaració de variables, p.e., int n; */
int fi_execucio = 0, user, n_usuaris, portUDPrem, bytes_rebuts, Sck=0, canal;
struct usuari * taula_usuaris = NULL;
char buffer[MAX_MISSATGE_PLUMI+1], tipus_missatge, IPrem[IP_LENGTH], adr_preguntador[MAX_USER_NICK+MAX_LEN_DOMINI+2];
char nickname[MAX_USER_NICK], domini_usuari[MAX_LEN_DOMINI], fitxer_log[MAX_NOM_FITXER];
char buffer2[300];
/* Expressions, estructures de control, crides a funcions, etc. */
printf("Estic al pas 1\n");
if ((n_usuaris = LlegirTaulaDesdeFitxer("/home/markus/ClionProjects/nodelumi2/MIp2-nodelumi.cfg"/*NOM_FITXER_CONFIG*/, &taula_usuaris)) == -1 ){
//LUMI_EscriureFitxerLog(NOM_FITXER_LOG, "Error al llegir el fitxer de configuracio");
//Apagar tots
return -1;
}
//Falta encapsular
printf("Estic al pas 2\n");
//LUMI_ResolNomFitxerLog('N', fitxer_log, DOMINI);
strcpy(fitxer_log, "temporal.log");
Sck = LUMI_InicialitzarNode(fitxer_log);
int llistaSck[] = {Sck};
canal = HaArribatAlgunaCosaEnTemps(llistaSck, 1, 0);
printf("Estic al pas 3");
bytes_rebuts = LUMI_RepLiniaDe(Sck,IPrem,&portUDPrem, buffer, sizeof(buffer)); //encarregat d'enviar el AI si el format es erroni
while(fi_execucio!=1){
if (bytes_rebuts <= 0){ //si hi ha hagut error
if(bytes_rebuts == -1){ //si s'ha produit un error inesperat
close(Sck);
return 1;
}
else if (bytes_rebuts == 0) return 1; //si s'ha tancat el socket
//si bytes_rebuts == -2 només volem omitir la linia rebuda, aixi que no fem res
}
else{
buffer[bytes_rebuts] = '\0';
tipus_missatge = buffer[0];
LUMI_DescodificarMissatge(tipus_missatge, buffer, adr_preguntador, domini_usuari, nickname);
switch(tipus_missatge){
case 'R':
printf("nick=%s\n",nickname);
if (strcmp(DOMINI,domini_usuari) != 0) { //no es del nostre domini
LUMI_EnviaResposta(Sck, 'N', adr_preguntador, IPrem, portUDPrem);
} else{ //L'usuari a registrar es del nostre domini
user = CercarUsuariPerNom(taula_usuaris, nickname, n_usuaris);
if (user < 0){//L'usuari no esta a la taula
LUMI_EnviaResposta(Sck, 'N', NULL, IPrem, portUDPrem);
}
else //L'usuari existeix dins la taula
{
if(taula_usuaris[user].UDP_port!=-1) { //evitem suplantació d'identitat
registrarUsuari(taula_usuaris, user, IPrem, portUDPrem);
sprintf(buffer2, "L'usuari %s amb IP %s i portUDP %i s'ha registrar correctament", taula_usuaris[user].nom, taula_usuaris[user].IP, taula_usuaris[user].UDP_port);
printf("%s\n", buffer2);
LUMI_EnviaResposta(Sck, 'K', NULL, IPrem, portUDPrem);
}
else{
LUMI_EnviaResposta(Sck,'O',adr_preguntador,IPrem,portUDPrem);
printf("No s'ha pogut registrar l'usuari %s, ja estava registrat\n", nickname);
}
}
}
break;
case 'D':
user = CercarUsuariPerIPiPort(taula_usuaris,IPrem, portUDPrem, n_usuaris);
if (user < 0){//L'usuari no esta a la taula
LUMI_EnviaResposta(Sck, 'N', NULL, IPrem, portUDPrem);
}
else //L'usuari existeix dins la taula
{
desregistrarUsuari(taula_usuaris, user);
sprintf(buffer2, "L'usuari %s amb IP %s s'ha desregistrat correctament", taula_usuaris[user].nom, taula_usuaris[user].IP, taula_usuaris[user].UDP_port);
printf("%s\n",buffer2);
LUMI_EnviaResposta(Sck, 'K', NULL, IPrem, portUDPrem);
}
break;
case 'L': //Aqui els buffers domini i nickname contenen la informació de l'usuari que es vol localitzar.
if(strcmp(domini_usuari, DOMINI) == 0)
{
sprintf(buffer2, "L'usuari %s intenta localitzar a algu", adr_preguntador);
printf("%s\n",buffer2);
user = CercarUsuariPerNom(taula_usuaris, nickname, n_usuaris); //farà referencia al usuari que es vol localitzar
if (user < 0) {
LUMI_EnviaResposta(Sck, 'N', adr_preguntador, IPrem, portUDPrem);
}
else if (taula_usuaris[user].UDP_port == -1){
LUMI_EnviaResposta(Sck, 'O', adr_preguntador, IPrem, portUDPrem); ///AIXO NO HA DE PORTAR ADR PREGUNTADOR
}
else{
LUMI_EnviaPeticioServeiLocalitzacio(Sck, adr_preguntador, taula_usuaris[user].IP, taula_usuaris[user].UDP_port);
}
}
else
{
if (ResolDNSaIP(domini_usuari, IPrem) < 0)
LUMI_MostraError("Error al resoldre direccio dns");
else {
LUMI_EnviaLiniaA(Sck, IPrem, UDP_PORT, buffer); //sense retransmissions
}
}
break;
case 'C':
case 'A': //En ambdos casos s'actua de la mateixa manera
if(strcmp(domini_usuari, DOMINI) == 0){
user = CercarUsuariPerNom(taula_usuaris, nickname, n_usuaris);
if (user >= 0){
strcpy(IPrem,taula_usuaris[user].IP);
portUDPrem = taula_usuaris[user].UDP_port;
LUMI_EnviaLiniaA(Sck, IPrem, portUDPrem, buffer); //sense retransmissions
}
else {
LUMI_MostraError("Problema al reenviar una peticio: L'usuari no existeix");
}
}
else{
if (ResolDNSaIP(domini_usuari, IPrem) < 0)
LUMI_MostraError("Error al resoldre direccio dns");
else {
LUMI_EnviaLiniaA(Sck, IPrem, UDP_PORT, buffer); //sense retransmissions
}
}
break;
default:
//Error en el format
break;
}
}
canal = HaArribatAlgunaCosaEnTemps(llistaSck, 1, 0);
bytes_rebuts = LUMI_RepLiniaDe(Sck,IPrem,&portUDPrem, buffer, sizeof(buffer)); //encarregat d'enviar el AI si el format es erroni
}
close(Sck);
return 0;
}

13
nodelumi2/MIp2-nodelumi.cfg Executable file
View File

@ -0,0 +1,13 @@
localhost
11
pepito
maria
el7at
pere.pi
7uring
lindefinit
crazyfrog
eustaki
mr.xarxes
Marc
Enric