la source est une application réalisé en C++ permettant la communication entre deux machines privées(qui se trouvent dans des sous réseaux protégés par une translation d'adresse)
une application client et une serveur sont disponibles dans le code source.
Source / Exemple :
///////////////
//Application client
//fichier p2pnat.cpp
#include "p2pnat.h"
using namespace std;
//déclarations des variables
char trame [9] ; //tableau pour les trames envoyées
char trame_recu [9] ;//tableau pour les trames recues
char buf2[5];//tableau pour les trames recues
char p_distant [9];//pour récupérer le port du noeud distant
char f_distant [9];//pour récupérer le flag du noeud distant
char ip_distant [9] ;//pour récupérer l'adresse ip du noeud distant
char ip_prive [] = "12.0.0.2";//configuration manuelle de l'adresse ip privé
int port_distant;//pour la valeur du port distant
int flag_distant;//pour la valeur du flag distant
int port_local_in;//pour la valeur du port local
bool etat; //pour définir si le noeud local est privé ou public
char punch_request [9] = "01010000";//pour tester si j'ai recu un punch_request du serveur
char close_request [9]="01100000";//préparer la trame close_request
char echo_recu[9]="01000000";//préparer la trame echo_request
char save_ack[9]="11010000";//pour tester si j'ai recu un acquittement
int flag_recu;//pour la valeur du flag distant
char user[9];//pour stocker la valeur de la commande donné par l'utilisateur
int pid;//pour les sous processus
int iden = 0; //pour l'identificateur du noeud distant donné par l'utilisateur
bool gg=true;//pour la boucle de la phase keep_alive
char mon_ip_publique [16];//pour stocker l'adresse ip publique recu du serveur
int port_publique;//pour la valeur du port publique
char mon_port_publique[6];//pour stocker le port public recu du serveur
int port_number;//pour le port du serveur ou de la machine distante
sockaddr_in local_info; //structure d'adresse pour l'attribution du socket avec le bind
//la fonction suivante prépare mon id
void set_mon_id(char tmp [])
{
tmp[0]='1';
tmp[1]='2';
tmp[2]='3';
}
//fonction qui teste si le fichier file.txt contient a comme premier caractère
bool tstfile()
{
//ouverture du fichier en mode lecture
FILE * fichier = fopen("file.txt","r");
if(fichier == NULL) {perror("fopen");}
//déclaration d'un tableau de caractère
char tmp[50];
//lire la première ligne
if(fgets(tmp,sizeof(tmp),fichier))
{ //si j'ai a comme premier caractère je retourne true
if(tmp[0] == 'a' ) return true;
}
//sinon je retourne false
return false;
}
//fonction qui efface le fichier file.txt
void setfile()
{
//ouvrir le fichier en mode écriture
FILE * fichier = fopen("file.txt","w");
//fermeture du fichier
fclose(fichier);
}
//fonction qui écrit aaaaaaaa dans le fichier file.txt afin de permettre de gérer
//le début et la fin de la phase keep_alive
void writefile()
{
//ouvrir le fichier en mode écriture
FILE * fichier = fopen("file.txt","w");
//en cas d'erreur d'ouverture
if(fichier == NULL) {perror("fopen");}
//ecrire 6 caractères a
fprintf(fichier,"aaaaaaa");
//fermer le fichier
fclose(fichier);
}
//pour tester le type du trame recu
bool cmp_type(char tmp1[], char tmp2[])
{
//le test est fait sur les 4 premier caractères
if (tmp1[0]==tmp2[0] and tmp1[1]==tmp2[1] and tmp1[2]==tmp2[2] and tmp1[3]==tmp2[3])
return true;
return false;
}
int create_socketUDP()
{
//permet de créer un socket UDP
int soket = socket(AF_INET,SOCK_DGRAM,0);
if (soket < 0) {perror("socket creation"); exit(1);}
return soket;
}
int create_socketTCP()
{
//permet de créer un socket TCP
int soket = socket(AF_INET,SOCK_STREAM,0);
if (soket < 0) {perror("socket creation"); exit(1);}
return soket;
}
in_addr * find_ip_server (char * server)
{
//cette fonction recoit le nom du serveur et retourne un pointeur sur l'adresse IP
// par exemple je recoit pcts07 et ca retourne un pointeur sur 160.98.31.137
hostent * struc = gethostbyname(server);
if (struc == NULL) { herror("gethostbyname failed"); exit(1);}
in_addr * addrpointer = (in_addr *) struc ->h_addr;
return addrpointer;
}
sockaddr_in desc_server(in_addr * pointeursuraddrserveur, int portnum)
{
//à l'aide du pointeur de la fonction find_ip_server et du numéro du port donné je forme la structure de serveur
// cette structure précise l'utilisation des adresse IP et transforme le numéro de port en forme réseau
sockaddr_in temp;
temp.sin_family = AF_INET;
temp.sin_addr = * pointeursuraddrserveur;
temp.sin_port = htons(portnum);
return temp;
}
int connect_request(int c, sockaddr_in server_info)
{
//permet de lancer une connexion TCP
int r = connect(c,(sockaddr *) &server_info,sizeof(server_info));
if (r<0) { perror("connect"); exit(1); }
return r;
}
//fonction principale de l'application client
int hello(int port_local,char * server_name, int port_server_number)
{
//préparer mes variables
bzero(mon_ip_publique,sizeof(mon_ip_publique));
bzero(mon_port_publique,sizeof(mon_port_publique));
port_publique = 0;
port_number = 0;
//copier la valeur de port_local dans la variable port_local_in
port_local_in = port_local;
//copier la valeur de port serveur dans la variable port_server_number
port_number = port_server_number;
//trouver l'adresse du serveur
in_addr * pointeur_addr = find_ip_server(server_name);
//préparer la structure de l'adresse du serveur
sockaddr_in server_info = desc_server(pointeur_addr, port_number);
//déclarer le socket TCP main_socket
int main_socket = create_socketTCP();
int r1; // pour le bind, attribution du socket à l'adresse ip et port local
//pour récupérer les informations de chaque noeud recherché
char fp [2];
char pp1 [6] ;
char ipp1 [16];
int f1;
int p1 = 0;
//////////////////////////////////////////////////////////
//préparer la structure d'adresse local
local_info.sin_family = AF_INET;//famille d'adresse IP
//attribuer le socket à l'adresse ip valide de la carte réseau de la machine
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in);//préciser le port local pour le socket
//attribuer le socket à l'adresse ip et le port de la machine
r1 = bind(main_socket,(sockaddr *) &local_info, sizeof(local_info));
// Se connecter au serveur
int r = connect_request(main_socket,server_info);
//en cas d'erreur de connexion
if (r<0) { perror("connect"); exit(1); }
cout << "***********************************************************" << endl;
cout << "*******************la phase découverte*****************" << endl;
bzero(trame,sizeof(trame));
//préparer le hello_request
strcpy(trame,"1010");
//envoyer le hello_request
r = send (main_socket,trame,strlen(trame),0);
if (r<0) {perror("rec"); exit(1);}
//attendre que le serveur demande l'identificateur de la machine locale
r = recv(main_socket,buf2,sizeof(buf2),0);
//pour assurer que le serveur demande l'id
if(strcmp(buf2,"1100")==0)
{
bzero(trame,sizeof(trame));
//préparer mon id dans la trame
set_mon_id(trame);
//envoyer mon id au serveur
r = send (main_socket,trame,sizeof(trame),0);
//attendre l'adresse ip publique envoyé par le serveur
r = recv(main_socket,mon_ip_publique,sizeof(mon_ip_publique),0);
cout << "mon ip publique est le: " <<mon_ip_publique << "\n" << endl;
bzero(mon_port_publique,sizeof(mon_port_publique));
//attendre le port publique envoyé par le serveur
r = recv(main_socket,mon_port_publique,sizeof(mon_port_publique),0);
sscanf(mon_port_publique,"%d",&port_publique);
cout << "mon port publique est le: " << port_publique << "\n" << endl;
}
cout << "mon ip prive est le: " <<ip_prive << "\n" << endl;
cout << "mon port prive est le: " << port_local_in << "\n" << endl;
cout << "******************************************************" << endl;
cout << "*********************la phase enregistrement**********" << endl;
//comparer les deux adresses ip afin de savoir si la machine est derrière un NAT ou pas
//si je suis en privée, je m'enregistre en indiquant au serveur que je suis en privé
if (strcmp(mon_ip_publique,ip_prive)!= 0)
{
cout << "je suis dans le réseau privé \n" << endl;
cout << "je dois m'enregistrer auprès du serveur \n" << endl;
//définir que je suis privé à travers le variable etat
etat = true;
bzero(trame,sizeof(trame));
//préparer le save_request_prive
strcpy(trame,"0010");
//envoyer le save_request_prive
r = send (main_socket,trame,strlen(trame),0);
if (r<0) {perror("send"); exit(1);}
//attendre l'acquittement
bzero(trame_recu,sizeof(trame_recu));
r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
//si j'ai recu l'acquittement??
if (cmp_type(trame_recu,save_ack))
{ cout << "je suis sauvé au serveur \n" << endl; }
else{
//si j'ai pas recu l'aquittement d'enregistrement, je signale l'erreur
cout << "erreur d'enregistrement \n" <<endl;
}
}
//si j'ai les mêmes adresses ip, alors je suis en public
else
{
cout << "je suis dans le réseau publique \n" << endl;
//définir que je suis en public à travers la variable etat
etat = false;
bzero(trame,sizeof(trame));
//préparer le save_request_public
strcpy(trame,"0011");
//envoyer le save_request_public
r = send (main_socket,trame,strlen(trame),0);
if (r<0) {perror("send"); exit(1);}
//attendre l'acquittement
bzero(trame_recu,sizeof(trame_recu));
r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
if (cmp_type(trame_recu,save_ack))
{ cout << "je suis sauvé au serveur \n" << endl; }
else{
cout << "erreur d'enregistrement \n" <<endl;
}
}
//si je suis en public
if(etat == false)
{
//je lance un boucle pour écouter toujours sur la ligne de commande
while( gg == true)
{
//j'écoute sur la ligne du commande
cin >> user;
//en cas d'erreur de création du sous processus
if ((pid=fork()) == -1)
{
perror("Erreur de creation de processus fils");
exit(1);
}
//créer le sous processus
if (pid == 0)
{
//si le client n'as pas tapé connect, je me mets en écoute en TCP sur un port = (port_local-1)
if(strcmp(user,"connect") != 0) {public_waiting_tcp();}
else
{
//si l'utilisateur demande d'établir une connexion
//pour arrêter la phase de keep_alive
setfile();
//pour sortir de la boucle
gg = false;
//l'application demande l'id du noeud avec le quel on veut communiquer
cout << "donnez l'id"<< endl;
//stocker la valeur donné par l'utilisateur dans la variable iden
cin >> iden;
cout << "************************************************************************" << endl;
cout << "**********************la phase recherche *******************************" << endl;
cout << "************************************************************************" << endl;
bzero(trame,sizeof(trame));
//préparer le search_request
strcpy(trame,"0111");
//envoyer le search_request
r = send (main_socket,trame,sizeof(trame),0);
bzero(trame_recu,sizeof(trame_recu));
//attendre l'acquittement
r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
//si je n'ai pas recu un acquittement, générer une erreur
if (!cmp_type(trame_recu,save_ack))
{ cout << "il y a un problème de request" << endl; exit(1);}
//préparer l'id du noeud distant
bzero(trame,sizeof(trame));
sprintf(trame,"%d",iden);
//envoyer l'id du noeud recherché
r = send (main_socket,trame,sizeof(trame),0);
cout << "********************************************************************" << endl;
cout << "on cherche la machine dont l'id est le: " << iden << endl;
//je vais recevoir les coordonnées du noeud recherché
r = recv(main_socket,fp,sizeof(fp),0);
if(r<0){perror("recv");}
//copier la valeur de flag du noeud recherché dans la variable f1
sscanf(fp,"%d",&f1);
//se préparer pour recevoir le port recherché
bzero(pp1,sizeof(pp1));
//mettre à zéro la variable pp1
strcpy(pp1,"000000");
r = recv(main_socket,pp1,sizeof(pp1),0);
if(r<0){perror("recv");}
//copier la valeur du port du noeud recherché dans p1
sscanf(pp1,"%d",&p1);
//pour recevoir l'adresse ip du noeud recherché
r = recv(main_socket,ipp1,sizeof(ipp1),0);
if(r<0){perror("recv");}
//stocker les informations du noeud rechercé reçu du serveur
strcpy(ip_distant,ipp1);//stocker l'adresse ip dans ip_distant
port_distant = p1;//stocker la valeur du port dans la variable port_distant
flag_distant = f1;//stocker la valeur du flag du noeud distant dans la variable flag_distant
flag_recu = f1; //stocker la valeur du flag du noeud distant dans la variable flag_recu
//afficher les information du noeud recherché
cout << "les information de la machine recherché : " << endl;
cout << "port : " << p1 << endl;
cout << "ip : " << ip_distant << endl;
if(f1==0){cout << "la machine recherché est privé" << endl; }
else {cout << "la machine recherché est public" << endl; }
cout << "********************************************************************" << endl;
cout << "**********************Fin de la phase recherche ********************" << endl;
cout << "********************************************************************" << endl;
}
}
}
}
//si je suis dans le réseau privé
else
{
//je donne la possiblité à l'utilisateur de lancer la phase keep_alive ou de lancer une demande de communication directement
//si je lance la phase de keep_alive, l'utilisateur pourra à n'importe quel moment lancer une demande de communication
cout << "tapez echo pour la phase keep_alive "<< endl;
cout << "sinon entrez l'id du noeud dont lequel vous voulez communiquer" << endl;
//boucle pour que l'application lit toujours sur la ligne du commande
while( gg == true)
{
//lire sur la ligne du commande
cin >> user;
//en cas d'erreur du création du sous processus
if ((pid=fork()) == -1)
{
perror("Erreur de creation de fils");
exit(1);
}
//création du sous processus
if (pid == 0)
{
//si l'utilisateur tape echo, alors il demande de lancer la phase de keep_alive
if(strcmp(user,"echo")==0)
{
//j'écris dans le fichier texte, lorsque j'efface le fichier texte, la phase de keep_alive s'arrête
writefile();
cout << "************************************************************************" << endl;
cout << "**********************la phase keep_alive ******************************" << endl;
cout << "************************************************************************" << endl;
//tant que le fichier texte n'est pas vide et commence par un a comme premier paramètre
while(tstfile()==true)
{
bzero(trame,sizeof(trame));
//préparer l'echo_request
strcpy(trame,"0100");
//envoyer l'echo_request
r = send (main_socket,trame,strlen(trame),0);
//attendre un echo_request du serveur ou un punch_request
bzero(trame_recu,sizeof(trame_recu));
r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
//si j'ai recu un punch_request du serveur, ca veut dire qu'il y a une machine qui cherche la machine locale
if (cmp_type(trame_recu,punch_request))
{
//j'efface le fichier file.txt pour arrêter la phase de keep_alive qui tourne en parallèle
setfile();
cout << "je suis recherché" << endl;
//je récupère les données du noeud cherchant
r = recv(main_socket,f_distant,sizeof(f_distant),0);
if(r<0){perror("recv");}
//je récupère le flag du noeud qui cherche la machine locale
sscanf(f_distant,"%d",&flag_distant);
//je recupère le port
r = recv(main_socket,p_distant,sizeof(p_distant),0);
if(r<0){perror("recv");}
sscanf(p_distant,"%d",&port_distant);
//je recupère l'adresse ip de la machine qui veut communiquer
bzero(ip_distant,sizeof(ip_distant));
r = recv(main_socket,ip_distant,sizeof(ip_distant),0);
if(r<0){perror("recv");}
//j'affiche les informations de la machine qui me cherche
cout << "****************************************************" << endl;
cout << "la machine distante qui me cherche : " << endl;
cout << "port distant: " << port_distant << endl;
cout << "ip distant: " << ip_distant << endl;
if(flag_distant == 0) {cout << "la machine distante est privé" << endl; }
else {cout << "la machine distante est public" << endl; }
cout << "****************************************************"<<endl;
//si la machine qui me cherche est privé
if(flag_distant == 0)
{
//et je suis privé, je retourne 1
if(etat==true)
{
cout << "je suis privé et demandé par un client privé" << endl;
//je ferme la connexion avec le serveur
close(main_socket);
return 1;
}
}
//si la machine qui veut communiquer est public
//la fonction retourne 3
if (flag_distant == 1)
{
cout << "je suis demandé par un client public" << endl;
cout << "je lance la procédure tcp_connect_public" << endl;
//je ferme la connexion avec le serveur
close(main_socket);
return 3;
}
}
//si j'ai pas recu un punch_request, alors je continue dans la phase du keep_alive
cout << "++" << endl;
sleep(5);
}
}//fermeture de if(strcmp(user,"echo")==0)
//à n'importe quel moment, le client pourra taper connect dans la ligne du commande
//afin de demander l'application de lancer une demande de communication avec une machine distante
if(strcmp(user,"connect") == 0)
{
//lorsque le client demande une communication, j'arrête la phase de keep_alive
setfile();
//j'arrête la boucle d'écoute sur la ligne du commande
gg = false;
//je demande à l'utilisateur l'id de la machine avec laquelle on va communiquer
cout << "donnez l'id"<< endl;
//je stocke l'id dans la variable iden
cin >> iden;
cout << "************************************************************************" << endl;
cout << "**********************la phase recherche *******************************" << endl;
cout << "************************************************************************" << endl;
bzero(trame,sizeof(trame));
//préparer le search_request
strcpy(trame,"0111");
//envoyer le search_request
r = send (main_socket,trame,sizeof(trame),0);
bzero(trame_recu,sizeof(trame_recu));
//attendre un acquittement
r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
//si j'ai pas reçu l'acquittement, signaler une erreur et sortir
if (!cmp_type(trame_recu,save_ack))
{ cout << "il y a un problème de request" << endl; exit(1);}
//si j'ai reçu un acquittement du serveur
bzero(trame,sizeof(trame));
//j'envoie au serveur l'id de la machine avec laquelle je veux communiquer
sprintf(trame,"%d",iden);
r = send (main_socket,trame,sizeof(trame),0);
cout << "********************************************************************" << endl;
cout << "on cherche la machine dont l'id est le: " << iden << endl;
//je vais recevoir les coordonnées du noeud distant
//variables pour la réception des informations de la machine distante
char fp [2];
char pp1 [6] ;
char ipp1 [16];
int f1;
int p1 = 0;
/////////////////////////////
//recevoir et stocker le flag de la machine distante
r = recv(main_socket,fp,sizeof(fp),0);
if(r<0){perror("recv");}
sscanf(fp,"%d",&f1);
//recevoir et stocker le port de la machine distante
bzero(pp1,sizeof(pp1));
strcpy(pp1,"000000");
r = recv(main_socket,pp1,sizeof(pp1),0);
if(r<0){perror("recv");}
sscanf(pp1,"%d",&p1);
//recevoir et stocker l'adresse ip publique de la machine distante
r = recv(main_socket,ipp1,sizeof(ipp1),0);
if(r<0){perror("recv");}
//charger les variables par les valeurs reçues du serveur
strcpy(ip_distant,ipp1);
port_distant = p1;
flag_distant = f1;
flag_recu = f1;
//afficher les informations de la machine recherché
cout << "les information de la machine recherché : " << endl;
cout << "port : " << p1 << endl;
cout << "ip : " << ip_distant << endl;
if(f1==0){cout << "la machine recherché est privé" << endl; }
else {cout << "la machine recherché est public" << endl; }
cout << "********************************************************************" << endl;
cout << "**********************Fin de la phase recherche ********************" << endl;
cout << "********************************************************************" << endl;
//si la machine distante est privée
if(flag_recu == 0)
{ //et si la machine locale est aussi privée
if(etat == false)
{
cout << "je suis public et je cherche un noeud privé" << endl;
//je ferme la connexion avec le serveur et retourne la valeur 5
close (main_socket);
return 5;
}
//si je suis une machine public
else
{
cout << "je suis privé et je cherche un noeud privé" << endl;
//je ferme la connexion avec le serveur et retourne 6
close(main_socket);
return 6;
}
}
//si la machine recherché est public
else if (flag_recu == 1)
{
//et si la machine locale est privée
if(etat == true)
{
cout <<"je suis privé et je cherche un noeud public"<<endl;
//je ferme la connexion avec le serveur et retourne 7
close(main_socket);
return 7;
}
//si la machine locale est aussi publique
else
{
cout <<"je suis public et je cherche un noeud public"<<endl;
//je ferme la connexion avec le serveur et retourne 8
close(main_socket);
return 8;
}
}
} // fermeture de if(strcmp(user,"connect") == 0)
} //fermeture de if (pid == 0)
} //fermeture de while gg = true
} //fermeture de else
return 0;
}
//cette fonction est lancé lorsque un client privé demande une connexion avec un client privée
//c'est le client qui a demandé la connexion qui lance cette fonction
//ca permet d'envoyer des requêtes UDP vers la machine distante, ces requêtes vont se servir des
//trous faites par la machine distante dans son NAT pour pouvoir arriver à destination
void udp_punching_prive()
{
cout << "debut du la phase udp punching_prive" << endl;
//former la structure de l'adresse du noeud distant pour le socket
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//créer le socket UDP
int udp_socket;
udp_socket = create_socketUDP();
//définir l'adresse et le port local pour les attribuer au socket
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in);
int b;
//attribuer le socket UDP à l'adresse ip et port local
b = bind(udp_socket,(sockaddr *) &local_info,sizeof(local_info));
if (b<0) { perror("bind"); exit (1);}
printf("ready\n");
//créer le sockaddr_in pour le noeud distant
sockaddr_in n_distant_info;
n_distant_info.sin_family = AF_INET;
n_distant_info.sin_addr = *addressptr;
n_distant_info.sin_port = htons(port_distant);
cout << "*************************************" << endl;
cout << "debut de la communication en UDP \n\n\n" << endl;
char message1 [] = "le protocole utilisé est UDP";
//envoyé un premier messge vers la machine distante
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
if (b < 0) {perror("sendto"); exit (1);}
printf("\n%s envoyé à %s:%d\n",message1,inet_ntoa(n_distant_info.sin_addr),port_distant);
//envoyer un deuxième message vers la machine distante
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
if (b < 0) {perror("sendto"); exit (1);}
printf("\n%s envoyé à %s:%d\n",message1,inet_ntoa(n_distant_info.sin_addr),port_distant);
cout << "Données recues en UDP \n\n\n" << endl;
//préparer un tableau des caractères pour la reception
char buffer[100];
//préparer une structure d'adresse pour la reception en UDP
struct sockaddr_in incoming_info;
unsigned int socklen;
socklen = sizeof(incoming_info);
//attendre une réponse de la machine distante
b = recvfrom(udp_socket,&buffer,sizeof(buffer)-1,0,(sockaddr *)&incoming_info,&socklen);
if (b<0) { perror("rcvfrom"); exit(1);}
buffer[b]=0;
//afficher la réponse reçu ainsi que l'adresse ip et le port de la machine distante
printf("de %s port %d, : %s\n",inet_ntoa(incoming_info.sin_addr),ntohs(incoming_info.sin_port),buffer);
cout << "Fin de la communication en UDP" << endl;
cout << "*************************************" << endl;
//fermer la connexion en UDP
close (udp_socket);
}
//cette fonction est appelé lorsqu'un client public demande une communication à un client aussi public
void public_connect_public()
{
cout << "je suis un noeud public et je connecte vers un noeud public " << endl;
//déclaration des variables
int r1;//pour le bind, send et recv
int tcp_socket;//pour le socket TCP utilisé
bool sortie = true;//pour arreter la communication lorsque je recois un exit
tcp_socket = create_socketTCP();
//préparer la structure de l'adresse de la machine distante
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//préparer la structure d'adresse local
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in);
//attribuer le socket à l'adresse ip et le port local
r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));
//créer le sockaddr_in pour le noeud distant
sockaddr_in n_distant_info;
n_distant_info.sin_family = AF_INET;
n_distant_info.sin_addr = *addressptr;
n_distant_info.sin_port = htons(port_distant-1); //car la machine publique écoute sur son port_local-1
//Se connecter à la machine distante qui est en écoute sur son port
r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
cout << buf_tcp << endl;
//envoyer des données
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
char text[100];
cout << "\n\\" << endl;
//tout ce que j'écris dans le terminal sera envoyé à la machine distante
while(sortie)
{
cin >> text ;
bzero(buf_tcp,sizeof(buf_tcp));
strcpy(buf_tcp,text);
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
//si je tape exit, la connexion TCP sera fermé
if(strcmp(text,"exit")==0) {cout << "connexion terminé"<< endl; close(tcp_socket); break; }
}
}
//cette fonction est appelé lorsqu'un noeud privé veut communiquer avec un noeud public
//fonctionnement semblable à public_connect_public
void prive_connect_public()
{
cout << "je suis un noeud privé et je connecte vers un noeud public " << endl;
int r1;
int tcp_socket;
bool sortie = true;
tcp_socket = create_socketTCP();
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//j'attribue le socket à l'adresse ip local et au port_local-1
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in-1);
r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));
//créer le sockaddr_in pour le noeud distant
sockaddr_in n_distant_info;
n_distant_info.sin_family = AF_INET;
n_distant_info.sin_addr = *addressptr;
n_distant_info.sin_port = htons(port_distant-1);//car la machine publique écoute sur son port_local-1
//Se connecter au serveur
r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
if(r1<0){perror("connect");}
else {
cout << "********************************************************************" << endl;
cout << "******************Debut de la communication TCP ********************" << endl;
}
char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
cout << buf_tcp << endl;
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
char text[100];
cout << "\n\\" << endl;
while(sortie)
{
cin >> text ;
bzero(buf_tcp,sizeof(buf_tcp));
strcpy(buf_tcp,text);
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
if(strcmp(buf_tcp,"exit")==0)
{
cout <<"************************" << endl;
cout << "connexion terminé" << endl;
cout << "**********************" << endl;
close(tcp_socket);
break;
}
}
}
//cette fonction est appelé lorsqu'un noeud découvre qu'il est public et l'utilisateur demande
//de se mettre en écoute
void public_waiting_tcp()
{
char buffer[100];
cout << "debut du la phase public waiting TCP" << endl;
//créer le socket
bool k = true;//pour afficher les données recues jusqu'à ce que je recois un exit
int tcp_socket;
tcp_socket = create_socketTCP();
//préparer la structure d'adresse local
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in-1);
//préparer une structure pour l'adresse ip et le port de la machine distante
struct sockaddr_in incoming_info;
unsigned int socklen;
char *who_is;
socklen = sizeof(incoming_info);
int b;
//attribuer le socket à l'adresse ip et le port local
b = bind(tcp_socket,(sockaddr *) &local_info,sizeof(local_info));
if (b<0) { perror("bind"); exit (1);}
//se mettre en écoute
b = listen(tcp_socket,1);
cout << "j'écoute sur le port: " << port_local_in-1 << endl;
int a;
int g;
//accepter les communications entrantes
a = accept(tcp_socket,(sockaddr *) &incoming_info,&socklen);
if(a<0) {perror("accept");}
else {
who_is = inet_ntoa(incoming_info.sin_addr);
printf("connexion accepté de %s:%d",who_is,htons(incoming_info.sin_port));
cout << "\n\n" << endl;
cout << "********************************************************************" << endl;
cout << "******************Debut de la communication TCP ********************" << endl;
}
g = recv(a,buffer,sizeof(buffer),0);
if(g<0) {perror("recv");}
cout << buffer << endl;
//afficher sur le terminal tout ce que je recois de la machine distante
while(k==true)
{
bzero(buffer,sizeof(buffer));
g = recv(a,buffer,sizeof(buffer),0);
if(g<0) {perror("recv");}
cout << buffer << endl;
if(strcmp(buffer,"exit")==0)
{
cout <<"************************" << endl;
cout << "connexion terminé" << endl;
cout << "**********************" << endl;
shutdown (tcp_socket,2);
break;
}
}
}
//cette fonction est appelé lorsqu'un noeud privé veut communiquer avec un noeud privé
//dans ce cas on appelle d'abord la fonction udp_punching_prive, pour communiquer d'abord en UDP
//et après on appelle la fonction tcp_connect pour réaliser la communication en TCP
void tcp_connect()
{
int r1;//pour le bind, send et recv
int tcp_socket;//déclarer le socket
bool sortie = true;//pour arreter la communication quand je recois un exit
tcp_socket = create_socketTCP();//créer le socket TCP
//former la structure de l'adresse du noeud distant pour le socket
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//définir l'adresse et le port local pour les attribuer au socket
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in+1);
//attrivuer le socket à l'adresse ip et le port lcocal+1
r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));
//créer le sockaddr_in pour le noeud distant
sockaddr_in n_distant_info;
n_distant_info.sin_family = AF_INET;
n_distant_info.sin_addr = *addressptr;
n_distant_info.sin_port = htons(port_distant+1);
/*sockaddr_in test;
int test_size = sizeof(test);*/
//Se connecter à la machine distante qui a ouverts les trous TCP dans son NAT
r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
if(r1<0){perror("connect");}
else
{
cout << "******************************************************************" << endl;
cout << "************Debut de communication en TCP*************************" << endl;
cout << "\n" << endl;
}
char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
cout << buf_tcp << endl;
//envoyer des données
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
cout << "\n\\" << endl;
char text[100];
//tout ce que j'écris sur le terminal s'envoie à l'autre machine
while(sortie)
{
cin >> text ;
//on lis de la ligne du commande
bzero(buf_tcp,sizeof(buf_tcp));
strcpy(buf_tcp,text);
bzero(text,sizeof(text));
if(strcmp(buf_tcp,"exit")==0)
{
//si c'est exit, on ferme la connexion
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
cout << "******************************************************************" << endl;
cout << "************Fin de communication en TCP*************************" << endl;
cout << "\n" << endl;
shutdown(tcp_socket,2);
break;
}
//sinon on envoie le texte écrit
r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
}
}
//cette fonction est appelé lorsqu'une machine privé est recherché par une machine public
//la machine public se met en attente et la machine privé initie la connexion TCP
void tcp_connect_public()
{
cout << "la phase lorsque le client privé est cherché par un client public" << endl;
//récuperer les informations du noeud distant
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//définir l'adresse et le port distants pour les attribuer au socket
sockaddr_in n_distant_info;
n_distant_info.sin_family = AF_INET;
n_distant_info.sin_addr = *addressptr;
n_distant_info.sin_port = htons(port_distant-1);
//créer le socket
int tcp_socket;
tcp_socket = create_socketTCP();
//définir l'adresse et le port local pour les attribuer au socket
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in-1);
int b;
bool sortie;
char buf_tcp[100];
char texte[100];
//attrivuer le socket à l'adresse ip et le port lcocal-1
b = bind(tcp_socket,(sockaddr *) &local_info,sizeof(local_info));
if (b<0) { perror("bind"); exit (1);}
//se connecter à la machine publique distante
b = connect(tcp_socket,(sockaddr *) &n_distant_info,sizeof(n_distant_info));
if(b<0){perror("connect");}
else {cout << "****************connexion établie en TCP************** " << endl; }
cout << "\n\\" << endl;
while(sortie)
{
cin >> texte;
bzero(buf_tcp,sizeof(buf_tcp));
strcpy(buf_tcp,texte);
b= send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
if(strcmp(buf_tcp,"exit")==0)
{
cout << "connexion terminée" << endl;
close (tcp_socket);
break;
}
}
}
//cette fonction est appelée lorsqu'une machine privée est recherché
//par une machine privée, la machine destinatrice appelle la fonction
//udp_punching pour ouvrir des trous udp et tcp dans son NAT afin de
//permettre au trafic venant de la station initiatrice de passer.
void udp_punching()
{
int i = 2;//définir le nombre de requêtes UDP et TCP envoyés pour
//ouvrir les trous dans le NAT (nombre = i*2 requêtes, soit
//dans ce cas, 4 requêts UDP et 4 requêtes TCP )
cout << "debut du la phase udp et tcp punching" << endl;
//récuperer les informations du noeud distant
hostent * n_distant;
in_addr * addressptr;
n_distant = gethostbyname(ip_distant);
if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
addressptr = (in_addr *) n_distant -> h_addr;
//créer le socket
int udp_socket;
udp_socket = create_socketUDP();
int tcp_socket_2;
tcp_socket_2 = create_socketTCP();
//définir une structure d'adresse pour l'adresse ip local et le port local
local_info.sin_family = AF_INET;
local_info.sin_addr.s_addr = htonl(INADDR_ANY);
local_info.sin_port = htons(port_local_in);
//définir une structure d'adresse pour l'adresse ip local et le port local+1 $
//pour la communication en TCP
sockaddr_in local_2;
local_2.sin_family = AF_INET;
local_2.sin_addr.s_addr = htonl(INADDR_ANY);
local_2.sin_port = htons(port_local_in+1);
int b;
//attribuer le socket UDP à l'adresse ip local et le port local
b = bind(udp_socket,(sockaddr *) &local_info,sizeof(local_info));
if (b<0) { perror("bind"); exit (1);}
int c;
//attribuer le socket TCP à l'adresse ip local et le port_local+1
c= bind(tcp_socket_2,(sockaddr *) &local_2,sizeof(local_2));
if (b<0) { perror("bind"); exit (1);}
//créer le sockaddr_in pour le noeud distant
//pour envoyer en UDP vers IPdistant: Pdistant
sockaddr_in n_distant_info_udp;
n_distant_info_udp.sin_family = AF_INET;
n_distant_info_udp.sin_addr = *addressptr;
n_distant_info_udp.sin_port = htons(port_distant);
//pour envoyer en UDP vers IPdistant: Pdistant+1
sockaddr_in n_distant_info_udp_2;
n_distant_info_udp_2.sin_family = AF_INET;
n_distant_info_udp_2.sin_addr = *addressptr;
n_distant_info_udp_2.sin_port = htons(port_distant+1);
//pour envoyer en TCP vers IPdistant: Pdistant
sockaddr_in n_distant_info_tcp;
n_distant_info_tcp.sin_family = AF_INET;
n_distant_info_tcp.sin_addr = *addressptr;
n_distant_info_tcp.sin_port = htons(port_distant);
//pour envoyer en UDP vers IPdistant: Pdistant+1
sockaddr_in n_distant_info_tcp_2;
n_distant_info_tcp_2.sin_family = AF_INET;
n_distant_info_tcp_2.sin_addr = *addressptr;
n_distant_info_tcp_2.sin_port = htons(port_distant+1);
char message1 [] = "punch_ my _ nat _UDP";
char message2 [] = "communication établie en UDP";
char buffer[100];
//pour le traffic entrant
struct sockaddr_in incoming_info;
unsigned int socklen;
socklen = sizeof(incoming_info);
//envoyer des requêtes UDP et TCP pour ouvrir les trous dans le NAT
while(i>0)
{
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info_udp,sizeof(n_distant_info_udp));
if (b < 0) {perror("sendto"); exit (1);}
printf("UDP: premier message envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_udp.sin_addr),port_distant);
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info_udp_2,sizeof(n_distant_info_udp_2));
if (b < 0) {perror("sendto"); exit (1);}
printf("UDP: deuxième message envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_udp_2.sin_addr),port_distant+1);
cout << "\n" << endl;
c = connect(tcp_socket_2,(sockaddr *)&n_distant_info_tcp,sizeof(n_distant_info_tcp));
printf("TCP: SYN envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_tcp.sin_addr),port_distant);
c = connect(tcp_socket_2,(sockaddr *)&n_distant_info_tcp_2,sizeof(n_distant_info_tcp_2));
printf("TCP: SYN envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_tcp_2.sin_addr),port_distant+1);
cout << "\n" << endl;
i=i-1;
}
cout << "**************************************************************************" << endl;
//attendre une réponse en UDP
b = recvfrom(udp_socket,&buffer,sizeof(buffer)-1,0,(sockaddr *)&incoming_info,&socklen);
if(b<0) { cout<< "rien recu en UDP" << endl; }
else{
cout << "communication établie en UDP avec " <<inet_ntoa(incoming_info.sin_addr)<< ":"<<htons(incoming_info.sin_port)<< endl;
cout << "Données recues en UDP" << endl;
cout << buffer << endl;
cout << "\n" << endl;
//répondre en UDP
b = sendto(udp_socket,message2,strlen(message2),MSG_EOR,(sockaddr *)&incoming_info,socklen);
cout << "Donnée envoyé en UDP: " << endl;
cout << message2 << endl;
cout << "\n" << endl;
}
cout << "Fin de la communication en UDP" << endl;
cout << "**************************************************************************" << endl;
//fermer la connexion UDP
close(udp_socket);
cout << "\n" << endl;
cout << "**************************************" << endl;
cout << "Début de la communication en TCP" << endl;
cout << "**************************************" << endl;
cout << "\n" << endl;
//la machine écoute en TCP sur son port_local+1
//la machine a déjà envoyé des requêtes de ce port source
c = listen(tcp_socket_2,1);
cout << "j'écoute sur le port " << port_local_in+1 << endl;
bool sortie = true;
char buf_tcp[99];
sockaddr_in client;
unsigned int client_size = sizeof(client);
char * who_is;
int g;
int a;
//accepter la connexion de la machine distante
a = accept(tcp_socket_2,(sockaddr *) &client,&client_size);
if(a < 0) {perror("accept"); exit(1);}
who_is = inet_ntoa(client.sin_addr);
printf("[connexion accepté de %s : %d]\n", who_is,htons(client.sin_port));
//pour recevoir les données textes de la machine distante
while(sortie)
{
bzero(buf_tcp,sizeof(buf_tcp));
g = recv(a,buf_tcp,sizeof(buf_tcp),0);
if(a<0) {perror("recv"); exit(1);}
//j'affiche tous jusqu'à ce que je recois un exit
cout << buf_tcp << endl;
if(strcmp(buf_tcp,"exit")==0) {
cout << "**************************************" << endl;
cout << "Fin de la communication TCP"<< endl;
cout << "**************************************" << endl;
close(a);//fermeture de la connexion TCP
break;
}
}
}
//fin fichier p2pnat.cpp
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.