Accueil > > > APPLICATION ENTRE DES MACHINES EN ZONES PRIVÉES
APPLICATION ENTRE DES MACHINES EN ZONES PRIVÉES
Information sur la source
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
Sources de la même categorie
Commentaires et avis
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.....)
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|