begin process at 2012 05 27 13:39:37
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Réseaux & Internet

 > APPLICATION ENTRE DES MACHINES EN ZONES PRIVÉES

APPLICATION ENTRE DES MACHINES EN ZONES PRIVÉES


 Information sur la source

Note :
Aucune note
Catégorie :Réseaux & Internet Classé sous :réseau, privé, translation, adressage, communication Niveau :Initié Date de création :13/11/2008 Vu / téléchargé :2 274 / 217

Auteur : jounyy07

Ecrire un message privé
Commentaire sur cette source (1)
Ajouter un commentaire et/ou une note

 Description

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

  • ///////////////
  • //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
///////////////
//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



 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources de la même categorie

Source avec Zip Source avec une capture MINI SERVEUR HTTP [WINDOWS] par ganjarasta
Source avec Zip Source avec une capture CLIENT DE TEST MODBUS TCP par brunovan
Source avec Zip Source avec une capture SCANIP [ARP / ICMP] par ganjarasta
Source avec Zip Source avec une capture TRACEROUTE [WINPCAP] par ganjarasta
Source avec Zip SERVEUR MULTITHREAD [LINUX/WIN] par nipepsinicolas

 Sources en rapport avec celle ci

Source avec Zip MODIFIER RAPIDEMENT SON FICHIER HOST par sholvaC
Source avec Zip Source avec une capture [C++] NAVIGATEUR INTERNET QT par pop70
Source avec une capture TRANSFERT DE FICHIER TCP [GCC - GTK] par ganjarasta
Source avec Zip TRANSLATION HOMOTHETIE ROTATION par randriano
Source avec Zip Source avec une capture FPS EN RÉSEAU par D6R26H59P

Commentaires et avis

Commentaire de omnia le 14/11/2008 13:45:50

Bonjour,

ta source est intéressante car tu fait de la communication UDP et TCP mais :

- cette source est plus en C adapté qu'en C++ (je ne vois pas de class ici)
- le niveau est débutant et non initié il faut pas exagéré
- tu dis :
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.

Que la transaction s'effectue sur un réseau privé, qu'il y ai du routage ou non, ici ca ne change rien au niveau du développement.

Au final la description serait plustôt : Exmple de client/serveur TCP & UDP

Bonne continuation et bon codage.

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

tutorial réseau c++ [ par paisibleman ] Bonjour ! Quelqu'un saurait il où je peux trouver un bon tutorial pour commencer la programation réseau en c++ ? Merci :) Communication entre fenetre [ par manu ] bonjour,je cherche a communiquer entre deux de mes programmes.je lance deux EXE ecrit en C et je voudrais que le projet 1 puisse passer des parametres plus de precisions pour la communication multiple stp !!! [ par Xs ] salut !bon, recement, j'ai posté un msg demandant comment faire plusieurs boites de dialog(cf : plusieurs dialogs [API])bon, comme dit, ca marche.mais Probleme Communication [ par fytlos ] Salut a tous,Voila je travaille sur une application distribuée ou l'on peut assimiler chaque entités a un programme en C++Dans le modele toutes les en Communication par socket [ par yoyo2 ] Bonjour à tous,est-il possible de communiquer par socket entre plusieurs systèmes différents. Par exemple envoyer des données entre un PC sous Windows Prog RNAAPP - Communication Modem [ par gevaen ] J'ai un petit problème : j'utilise un composant COM pour lancer rnaapp sous Windows CE. Ce composant est appelé à partir d'une page ASP pour effectuer Communication Modem, C++ [ par youne ] Je souhaiterais communiquer avec un modem sur le port COM. Comment composer le numero de telephone pour connecter le modem???? Threads et heap privé [ par mzhunix ] Salut à tous,je crée un heap privé "hHeapPrivate" dans le thread principale avec HeapCreate j'alloue quelques pointeurs dessus puis je crée un autre t Récupérer Domaine/Workgroup des pc du réseau [ par jefy ] JefyJ'utilise Builder6 et je cherche le moyen de récupérer les Domaines ou Workgroups du réseau (accessoirement les pc qui en font partie).merci d'ava Communication entre 2 applications [ par sena ] bonjour,Voila mon pb:J'ai un serveur UDP qui me récupère un entier.Ce serveur est en C.Ce que je voudrais c'est qu'une appli extérieure(VB, Fox.....)


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,624 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales