Application entre des machines en zones privées

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 / Exemple :


///////////////
//Application client 
//fichier p2pnat.cpp

#include "p2pnat.h"

using namespace std;

//déclarations des variables
char trame [9] ; //tableau pour les trames envoyées
char trame_recu [9] ;//tableau pour les trames recues
char buf2[5];//tableau pour les trames recues

char p_distant [9];//pour récupérer le port du noeud distant
char f_distant [9];//pour récupérer le flag du noeud distant
char ip_distant [9] ;//pour récupérer l'adresse ip du noeud distant

char ip_prive [] = "12.0.0.2";//configuration manuelle de l'adresse ip privé

int port_distant;//pour la valeur du port distant
int flag_distant;//pour la valeur du flag distant
int port_local_in;//pour la valeur du port local

bool etat; //pour définir si le noeud local est privé ou public

char punch_request [9] = "01010000";//pour tester si j'ai recu un punch_request du serveur

char close_request [9]="01100000";//préparer la trame close_request
char echo_recu[9]="01000000";//préparer la trame echo_request

char save_ack[9]="11010000";//pour tester si j'ai recu un acquittement
int flag_recu;//pour la valeur du flag distant

char user[9];//pour stocker la valeur de la commande donné par l'utilisateur

int pid;//pour les sous processus
int iden = 0; //pour l'identificateur du noeud distant donné par l'utilisateur

bool gg=true;//pour la boucle de la phase keep_alive

char mon_ip_publique [16];//pour stocker l'adresse ip publique recu du serveur
int port_publique;//pour la valeur du port publique
char mon_port_publique[6];//pour stocker le port public recu du serveur
int port_number;//pour le port du serveur ou de la machine distante

sockaddr_in local_info; //structure d'adresse pour l'attribution du socket avec le bind

//la fonction suivante prépare mon id
void set_mon_id(char tmp [])
{
    tmp[0]='1';
    tmp[1]='2';
    tmp[2]='3';

}

//fonction qui teste si le fichier file.txt contient a comme premier caractère
bool tstfile()
{
    //ouverture du fichier en mode lecture
   FILE * fichier = fopen("file.txt","r");
   if(fichier == NULL) {perror("fopen");}
    //déclaration d'un tableau de caractère
   char tmp[50];
   //lire la première ligne
   if(fgets(tmp,sizeof(tmp),fichier))
   {    //si j'ai a comme premier caractère je retourne true
       if(tmp[0] == 'a' ) return true;
   }
   //sinon je retourne false
   return false;
}

//fonction qui efface le fichier file.txt
void setfile()
{
    //ouvrir le fichier en mode écriture
    FILE * fichier = fopen("file.txt","w");
    //fermeture du fichier
    fclose(fichier);

}

//fonction qui écrit aaaaaaaa dans le fichier file.txt afin de permettre de gérer
//le début et la fin de la phase keep_alive
void writefile()
{
    //ouvrir le fichier en mode écriture
   FILE * fichier = fopen("file.txt","w");
   //en cas d'erreur d'ouverture
   if(fichier == NULL) {perror("fopen");}
   //ecrire 6 caractères a
   fprintf(fichier,"aaaaaaa");
   //fermer le fichier
   fclose(fichier);
}
//pour tester le type du trame recu
bool cmp_type(char tmp1[], char tmp2[])
{
    //le test est fait sur les 4 premier caractères
    if (tmp1[0]==tmp2[0] and tmp1[1]==tmp2[1] and tmp1[2]==tmp2[2] and tmp1[3]==tmp2[3])
    return true;
    return false;
}

int create_socketUDP()
{
    //permet de créer un socket UDP
    int soket = socket(AF_INET,SOCK_DGRAM,0);
    if (soket < 0) {perror("socket creation"); exit(1);}
    return soket;
}

int create_socketTCP()
{
    //permet de créer un socket TCP
    int soket = socket(AF_INET,SOCK_STREAM,0);
    if (soket < 0) {perror("socket creation"); exit(1);}
    return soket;
}

in_addr * find_ip_server (char * server)
{
    //cette fonction recoit le nom du serveur et retourne un pointeur sur l'adresse IP
    // par exemple je recoit pcts07 et ca retourne un pointeur sur 160.98.31.137
    hostent * struc = gethostbyname(server);
    if (struc == NULL) { herror("gethostbyname failed"); exit(1);}
    in_addr * addrpointer = (in_addr *) struc ->h_addr;
    return addrpointer;
}

sockaddr_in desc_server(in_addr * pointeursuraddrserveur, int portnum)
{
    //à l'aide du pointeur de la fonction find_ip_server et du numéro du port donné je forme la structure de serveur
    // cette structure précise l'utilisation des adresse IP et transforme le numéro de port en forme réseau
    sockaddr_in temp;
    temp.sin_family = AF_INET;
    temp.sin_addr = * pointeursuraddrserveur;
    temp.sin_port = htons(portnum);
    return temp;
}

int connect_request(int c, sockaddr_in server_info)
{
    //permet de lancer une connexion TCP
    int r = connect(c,(sockaddr *) &server_info,sizeof(server_info));
    if (r<0) { perror("connect"); exit(1); }
    return r;
}

//fonction principale de l'application client
int hello(int port_local,char * server_name, int port_server_number)
{
    //préparer mes variables
    bzero(mon_ip_publique,sizeof(mon_ip_publique));
    bzero(mon_port_publique,sizeof(mon_port_publique));
    port_publique = 0;
    port_number = 0;
    //copier la valeur de port_local dans la variable port_local_in
    port_local_in = port_local;
    //copier la valeur de port serveur dans la variable port_server_number
    port_number = port_server_number;
    //trouver l'adresse du serveur
    in_addr * pointeur_addr = find_ip_server(server_name);
    //préparer la structure de l'adresse du serveur
    sockaddr_in server_info = desc_server(pointeur_addr, port_number);
    //déclarer le socket TCP main_socket
    int main_socket = create_socketTCP();

    int r1; // pour le bind, attribution du socket à l'adresse ip et port local

    //pour récupérer les informations de chaque noeud recherché
    char fp [2];
    char pp1 [6] ;
    char ipp1 [16];
    int f1;
    int p1 = 0;
    //////////////////////////////////////////////////////////

        //préparer la structure d'adresse local
        local_info.sin_family = AF_INET;//famille d'adresse IP
		//attribuer le socket à l'adresse ip valide de la carte réseau de la machine
        local_info.sin_addr.s_addr = htonl(INADDR_ANY);
        local_info.sin_port = htons(port_local_in);//préciser le port local pour le socket

        //attribuer le socket à l'adresse ip et le port de la machine
        r1 = bind(main_socket,(sockaddr *) &local_info, sizeof(local_info));

      // Se connecter au serveur
      int r = connect_request(main_socket,server_info);
      //en cas d'erreur de connexion
      if (r<0) { perror("connect"); exit(1); }

  cout << "***********************************************************" << endl;
  cout << "*******************la phase découverte*****************" << endl;

    bzero(trame,sizeof(trame));
    //préparer le hello_request
    strcpy(trame,"1010");
    //envoyer le hello_request
    r = send (main_socket,trame,strlen(trame),0);
    if (r<0) {perror("rec"); exit(1);}

    //attendre que le serveur demande l'identificateur de la machine locale
     r = recv(main_socket,buf2,sizeof(buf2),0);
     //pour assurer que le serveur demande l'id
     if(strcmp(buf2,"1100")==0)
     {
        bzero(trame,sizeof(trame));
        //préparer mon id dans la trame
        set_mon_id(trame);
        //envoyer mon id au serveur
        r = send (main_socket,trame,sizeof(trame),0);

        //attendre l'adresse ip publique envoyé par le serveur
        r = recv(main_socket,mon_ip_publique,sizeof(mon_ip_publique),0);
        cout << "mon ip publique est le:  " <<mon_ip_publique << "\n" << endl;

        bzero(mon_port_publique,sizeof(mon_port_publique));
        //attendre le port publique envoyé par le serveur
        r = recv(main_socket,mon_port_publique,sizeof(mon_port_publique),0);
        sscanf(mon_port_publique,"%d",&port_publique);
        cout << "mon port publique est le:  " << port_publique << "\n" << endl;

     }

     cout << "mon ip prive est le:  " <<ip_prive << "\n" << endl;
     cout << "mon port prive est le:  " << port_local_in << "\n" << endl;

     cout << "******************************************************" << endl;
     cout << "*********************la phase enregistrement**********" << endl;
    //comparer les deux adresses ip afin de savoir si la machine est derrière un NAT ou pas
    //si je suis en privée, je m'enregistre en indiquant au serveur que je suis en privé
    if (strcmp(mon_ip_publique,ip_prive)!= 0)
    {

    cout << "je suis dans le réseau privé \n" << endl;
    cout << "je dois m'enregistrer auprès du serveur \n" << endl;
    //définir que je suis privé à travers le variable etat
    etat = true;

    bzero(trame,sizeof(trame));
    //préparer le save_request_prive
    strcpy(trame,"0010");
    //envoyer le save_request_prive
    r = send (main_socket,trame,strlen(trame),0);
    if (r<0) {perror("send"); exit(1);}

    //attendre l'acquittement
    bzero(trame_recu,sizeof(trame_recu));
    r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
    //si j'ai recu l'acquittement??
    if (cmp_type(trame_recu,save_ack))
        { cout << "je suis sauvé au serveur \n" << endl;  }
    else{
        //si j'ai pas recu l'aquittement d'enregistrement, je signale l'erreur
        cout << "erreur d'enregistrement \n" <<endl;

        }
    }

    //si j'ai les mêmes adresses ip, alors je suis en public
    else
    {
        cout << "je suis dans le réseau publique \n" << endl;        
        //définir que je suis en public à travers la variable etat
        etat = false;

        bzero(trame,sizeof(trame));
        //préparer le save_request_public
        strcpy(trame,"0011");
        //envoyer le save_request_public
        r = send (main_socket,trame,strlen(trame),0);
        if (r<0) {perror("send"); exit(1);}

        //attendre l'acquittement
        bzero(trame_recu,sizeof(trame_recu));
        r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
        if (cmp_type(trame_recu,save_ack))
            { cout << "je suis sauvé au serveur \n" << endl; }
        else{
            cout << "erreur d'enregistrement \n" <<endl;

            }

    }

    //si je suis en public
    if(etat == false)
    {
      //je lance un boucle pour écouter toujours sur la ligne de commande
      while( gg == true)
     {
    //j'écoute sur la ligne du commande
    cin >> user;
    //en cas d'erreur de création du sous processus
    if ((pid=fork()) == -1)
     {
     perror("Erreur de creation de processus fils");
     exit(1);
     }

     //créer le sous processus
     if (pid == 0)
     {
    //si le client n'as pas tapé connect, je me mets en écoute en TCP sur un port = (port_local-1)
    if(strcmp(user,"connect") != 0) {public_waiting_tcp();}

    else
      {
         //si l'utilisateur demande d'établir une connexion
         //pour arrêter la phase de keep_alive
         setfile();
        //pour sortir de la boucle
        gg = false;
        //l'application demande l'id du noeud avec le quel on veut communiquer
        cout << "donnez l'id"<< endl;
        //stocker la valeur donné par l'utilisateur dans la variable iden
        cin >> iden;

        cout << "************************************************************************" << endl;
        cout << "**********************la phase recherche *******************************" << endl;
        cout << "************************************************************************" << endl;

        bzero(trame,sizeof(trame));
        //préparer le search_request
        strcpy(trame,"0111");
        //envoyer le search_request
        r = send (main_socket,trame,sizeof(trame),0);
        bzero(trame_recu,sizeof(trame_recu));
         //attendre l'acquittement
         r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
         //si je n'ai pas recu un acquittement, générer une erreur
        if (!cmp_type(trame_recu,save_ack))
        { cout << "il y a un problème de request" << endl; exit(1);}

        //préparer l'id du noeud distant
        bzero(trame,sizeof(trame));
        sprintf(trame,"%d",iden);
        //envoyer l'id du noeud recherché
        r = send (main_socket,trame,sizeof(trame),0);
        cout << "********************************************************************" << endl;
        cout << "on cherche la machine dont l'id est le:  "  << iden << endl;
          //je vais recevoir les coordonnées du noeud recherché
		r =  recv(main_socket,fp,sizeof(fp),0);
		if(r<0){perror("recv");}
	//copier la valeur de flag du noeud recherché dans la variable f1
		sscanf(fp,"%d",&f1);
	
		//se préparer pour recevoir le port recherché
		bzero(pp1,sizeof(pp1));
		//mettre à zéro la variable pp1
		strcpy(pp1,"000000");
		r =  recv(main_socket,pp1,sizeof(pp1),0);
		if(r<0){perror("recv");}
		//copier la valeur du port du noeud recherché dans p1
		sscanf(pp1,"%d",&p1);

		//pour recevoir l'adresse ip du noeud recherché
		r =  recv(main_socket,ipp1,sizeof(ipp1),0);
		if(r<0){perror("recv");}

		//stocker les informations du noeud rechercé reçu du serveur
		strcpy(ip_distant,ipp1);//stocker l'adresse ip dans ip_distant
		port_distant = p1;//stocker la valeur du port dans la variable port_distant
		flag_distant = f1;//stocker la valeur du flag du noeud distant dans la variable flag_distant
		flag_recu = f1; //stocker la valeur du flag du noeud distant dans la variable flag_recu
		//afficher les information du noeud recherché
			cout << "les information de la machine recherché  : " << endl;
			cout << "port : " << p1 << endl;
			cout << "ip : " << ip_distant << endl;
			if(f1==0){cout << "la machine recherché est privé" << endl; } 
			else {cout << "la machine recherché est public" << endl; }
cout << "********************************************************************" << endl;
cout << "**********************Fin de la phase recherche ********************" << endl;
cout << "********************************************************************" << endl;

                             }
                        }
                }

        }
        //si je suis dans le réseau privé
        else
        {
            //je donne la possiblité à l'utilisateur de lancer la phase keep_alive ou de lancer une demande de communication directement
            //si je lance la phase de keep_alive, l'utilisateur pourra à n'importe quel moment lancer une demande de communication
cout << "tapez echo pour la phase keep_alive "<< endl; 
cout << "sinon entrez l'id du noeud dont lequel vous voulez communiquer" << endl;

            //boucle pour que l'application lit toujours sur la ligne du commande
		while( gg == true)
		{
		//lire sur la ligne du commande
		cin >> user;
	
		//en cas d'erreur du création du sous processus
		if ((pid=fork()) == -1)
		{
		perror("Erreur de creation de fils");
		exit(1);
		}
		//création du sous processus
		if (pid == 0)
		{

		//si l'utilisateur tape echo, alors il demande de lancer la phase de keep_alive
		if(strcmp(user,"echo")==0)
		{
		//j'écris dans le fichier texte, lorsque j'efface le fichier texte, la phase de keep_alive s'arrête
		writefile();
cout << "************************************************************************" << endl;
cout << "**********************la phase keep_alive ******************************" << endl;
cout << "************************************************************************" << endl;

	//tant que le fichier texte n'est pas vide et commence par un a comme premier paramètre
	while(tstfile()==true)
		{

		bzero(trame,sizeof(trame));
		//préparer l'echo_request
		strcpy(trame,"0100");
		//envoyer l'echo_request
		r = send (main_socket,trame,strlen(trame),0);

		//attendre un echo_request du serveur ou un punch_request
		bzero(trame_recu,sizeof(trame_recu));
		r =  recv(main_socket,trame_recu,sizeof(trame_recu),0);
	
	//si j'ai recu un punch_request du serveur, ca veut dire qu'il y a une machine qui cherche la machine locale
if (cmp_type(trame_recu,punch_request))
	{
		//j'efface le fichier file.txt pour arrêter la phase de keep_alive qui tourne en parallèle
	setfile();
	cout << "je suis recherché" << endl;

		//je récupère les données du noeud cherchant
		r =  recv(main_socket,f_distant,sizeof(f_distant),0);
		if(r<0){perror("recv");}
		//je récupère le flag du noeud qui cherche la machine locale
		sscanf(f_distant,"%d",&flag_distant);

		//je recupère le port
		r =  recv(main_socket,p_distant,sizeof(p_distant),0);
		if(r<0){perror("recv");}
		sscanf(p_distant,"%d",&port_distant);

		//je recupère l'adresse ip de la machine qui veut communiquer
		bzero(ip_distant,sizeof(ip_distant));
		r =  recv(main_socket,ip_distant,sizeof(ip_distant),0);
		if(r<0){perror("recv");}

		//j'affiche les informations de la machine qui me cherche
		cout << "****************************************************" << endl;
		cout << "la machine distante qui me cherche : " << endl;
		cout << "port distant: " << port_distant << endl;
		cout << "ip distant: " << ip_distant << endl;
		if(flag_distant == 0) {cout << "la machine distante est privé" << endl; } 
		else {cout << "la machine distante est public" << endl; }
		cout << "****************************************************"<<endl;

		//si la machine qui me cherche est privé
		if(flag_distant == 0)
		{
		//et je suis privé, je retourne 1
			if(etat==true)
				{
		cout << "je suis privé et demandé par un client privé" << endl;
				//je ferme la connexion avec le serveur
				close(main_socket);
				return 1;
				}
		}
		//si la machine qui veut communiquer est public
		//la fonction retourne 3
		if (flag_distant == 1)
		{
		cout << "je suis demandé par un client public" << endl;
		cout << "je lance la procédure tcp_connect_public" << endl;
		//je ferme la connexion avec le serveur
		close(main_socket);
		return 3;
		}

		}
//si j'ai pas recu un punch_request, alors je continue dans la phase du keep_alive
	cout << "++" << endl;
		sleep(5);

	}
}//fermeture de  if(strcmp(user,"echo")==0)
//à n'importe quel moment, le client pourra taper connect dans la ligne du commande
//afin de demander l'application de lancer une demande de communication avec une machine distante
if(strcmp(user,"connect") == 0)
		{
	//lorsque le client demande une communication, j'arrête la phase de keep_alive
									
		setfile();
		//j'arrête la boucle d'écoute sur la ligne du commande
		gg = false;
		//je demande à l'utilisateur l'id de la machine avec laquelle on va communiquer
		cout << "donnez l'id"<< endl;
		//je stocke l'id dans la variable iden
		cin >> iden;

		cout << "************************************************************************" << endl;
		cout << "**********************la phase recherche *******************************" << endl;
		cout << "************************************************************************" << endl;

		bzero(trame,sizeof(trame));
		//préparer le search_request
		strcpy(trame,"0111");
		//envoyer le search_request
		r = send (main_socket,trame,sizeof(trame),0);
		bzero(trame_recu,sizeof(trame_recu));
		//attendre un acquittement
		r = recv(main_socket,trame_recu,sizeof(trame_recu),0);
		//si j'ai pas reçu l'acquittement, signaler une erreur et sortir
		if (!cmp_type(trame_recu,save_ack))
		{ cout << "il y a un problème de request" << endl; exit(1);}

		//si j'ai reçu un acquittement du serveur
		bzero(trame,sizeof(trame));
		//j'envoie au serveur l'id de la machine avec laquelle je veux communiquer
		sprintf(trame,"%d",iden);
		r = send (main_socket,trame,sizeof(trame),0);
		cout << "********************************************************************" << endl;
		cout << "on cherche la machine dont l'id est le:  "  << iden << endl;

		//je vais recevoir les coordonnées du noeud distant
		//variables pour la réception des informations de la machine distante
		char fp [2];
		char pp1 [6] ;
		char ipp1 [16];
		int f1;
		int p1 = 0;
		/////////////////////////////

		//recevoir et stocker le flag de la machine distante
		r =  recv(main_socket,fp,sizeof(fp),0);
		if(r<0){perror("recv");}
		sscanf(fp,"%d",&f1);

		//recevoir et stocker le port de la machine distante
		bzero(pp1,sizeof(pp1));
		strcpy(pp1,"000000");
		r =  recv(main_socket,pp1,sizeof(pp1),0);
		if(r<0){perror("recv");}
		sscanf(pp1,"%d",&p1);

		//recevoir et stocker l'adresse ip publique de la machine distante
		r =  recv(main_socket,ipp1,sizeof(ipp1),0);
		if(r<0){perror("recv");}

		//charger les variables par les valeurs reçues du serveur
		strcpy(ip_distant,ipp1);
		port_distant = p1;
		flag_distant = f1;
		flag_recu = f1;
		//afficher les informations de la machine recherché
		cout << "les information de la machine recherché  : " << endl;
		cout << "port : " << p1 << endl;
		cout << "ip : " << ip_distant << endl;
		if(f1==0){cout << "la machine recherché est privé" << endl; }
		else {cout << "la machine recherché est public" << endl; }
		cout << "********************************************************************" << endl;
		cout << "**********************Fin de la phase recherche ********************" << endl;
		cout << "********************************************************************" << endl;

             //si la machine distante est privée
             if(flag_recu == 0)
            {   //et si la machine locale est aussi privée
                if(etat == false)
                {
                    cout << "je suis public et je cherche un noeud privé" << endl;
                    //je ferme la connexion avec le serveur et retourne la valeur 5
                    close (main_socket);
                    return 5;
                }
                //si je suis une machine public
                else
                {
                     cout << "je suis privé et je cherche un noeud privé" << endl;
                     //je ferme la connexion avec le serveur et retourne 6
                     close(main_socket);
                     return 6;
                }

            }

                //si la machine recherché est public
                else if (flag_recu == 1)
                    {
                            //et si la machine locale est privée
				if(etat == true)
				{
				cout <<"je suis privé et je cherche un noeud public"<<endl;
				//je ferme la connexion avec le serveur et retourne 7
								
				close(main_socket);
				return 7;
				}
				//si la machine locale est aussi publique
				else
								
				{
					cout <<"je suis public et je cherche un noeud public"<<endl;
                                //je ferme la connexion avec le serveur et retourne 8
                                close(main_socket);
                                return 8;
                            }
                    }

                        } // fermeture de   if(strcmp(user,"connect") == 0)
            } //fermeture de  if (pid == 0)
        } //fermeture de while gg = true

    } //fermeture de else

return 0;

}

//cette fonction est lancé lorsque un client privé demande une connexion avec un client privée
//c'est le client qui a demandé la connexion qui lance cette fonction
//ca permet d'envoyer des requêtes UDP vers la machine distante, ces requêtes vont se servir des
//trous faites par la machine distante dans son NAT pour pouvoir arriver à destination
void  udp_punching_prive()
  {
      cout << "debut du la phase udp punching_prive" << endl;

      //former la structure de l'adresse du noeud distant pour le socket

      hostent * n_distant;
      in_addr * addressptr;
      n_distant = gethostbyname(ip_distant);
      if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
      addressptr = (in_addr *) n_distant -> h_addr;

      //créer le socket UDP
      int udp_socket;
      udp_socket = create_socketUDP();

      //définir l'adresse et le port local pour les attribuer au socket
      local_info.sin_family = AF_INET;
      local_info.sin_addr.s_addr = htonl(INADDR_ANY);
      local_info.sin_port = htons(port_local_in);

      int b;
      //attribuer le socket UDP à l'adresse ip et port local
      b = bind(udp_socket,(sockaddr *) &local_info,sizeof(local_info));
      if (b<0) { perror("bind"); exit (1);}
      printf("ready\n");

      //créer le sockaddr_in pour le noeud distant
      sockaddr_in n_distant_info;
      n_distant_info.sin_family = AF_INET;
      n_distant_info.sin_addr = *addressptr;
      n_distant_info.sin_port = htons(port_distant);

      cout << "*************************************" << endl;
      cout << "debut de la communication en UDP \n\n\n" << endl;

      char message1 [] = "le protocole utilisé est UDP";
      //envoyé un premier messge vers la machine distante
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
		if (b < 0) {perror("sendto"); exit (1);}
      printf("\n%s envoyé à %s:%d\n",message1,inet_ntoa(n_distant_info.sin_addr),port_distant);

      //envoyer un deuxième message vers la machine distante
b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
      if (b < 0) {perror("sendto"); exit (1);}
      printf("\n%s envoyé à %s:%d\n",message1,inet_ntoa(n_distant_info.sin_addr),port_distant);

      cout << "Données recues en UDP \n\n\n" << endl;

      //préparer un tableau des caractères pour la reception
      char buffer[100];
      //préparer une structure d'adresse pour la reception en UDP
      struct sockaddr_in incoming_info;
      unsigned int socklen;
      socklen = sizeof(incoming_info);

      //attendre une réponse de la machine distante
      b = recvfrom(udp_socket,&buffer,sizeof(buffer)-1,0,(sockaddr *)&incoming_info,&socklen);
      if (b<0) { perror("rcvfrom"); exit(1);}
      buffer[b]=0;
      //afficher la réponse reçu ainsi que l'adresse ip et le port de la machine distante
printf("de %s port %d, : %s\n",inet_ntoa(incoming_info.sin_addr),ntohs(incoming_info.sin_port),buffer);

      cout << "Fin de la communication en UDP" << endl;
      cout << "*************************************" << endl;
      //fermer la connexion en UDP
      close (udp_socket);

      }

//cette fonction est appelé lorsqu'un client public demande une communication à un client aussi public
void  public_connect_public()
  {
      cout << "je suis un noeud public et je connecte vers un noeud public " << endl;
        //déclaration des variables
        int r1;//pour le bind, send et recv
        int tcp_socket;//pour le socket TCP utilisé
        bool sortie = true;//pour arreter la communication lorsque je recois un exit
        tcp_socket = create_socketTCP();

      //préparer la structure de l'adresse de la machine distante
      hostent * n_distant;
      in_addr * addressptr;
      n_distant = gethostbyname(ip_distant);
      if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
      addressptr = (in_addr *) n_distant -> h_addr;

        //préparer la structure d'adresse local
        local_info.sin_family = AF_INET;
        local_info.sin_addr.s_addr = htonl(INADDR_ANY);
        local_info.sin_port = htons(port_local_in);

        //attribuer le socket à l'adresse ip et le port local
        r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));

      //créer le sockaddr_in pour le noeud distant
      sockaddr_in n_distant_info;
      n_distant_info.sin_family = AF_INET;
      n_distant_info.sin_addr = *addressptr;
      n_distant_info.sin_port = htons(port_distant-1); //car la machine publique écoute sur son port_local-1

   //Se connecter à la machine distante qui est en écoute sur son port
  r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
  char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
  cout << buf_tcp << endl;
  //envoyer des données
  r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
  char text[100];

    cout << "\n\\" << endl;
    //tout ce que j'écris dans le terminal sera envoyé à la machine distante
  while(sortie)
  {
      cin >> text ;
      bzero(buf_tcp,sizeof(buf_tcp));
      strcpy(buf_tcp,text);
      r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
      //si je tape exit, la connexion TCP sera fermé
      if(strcmp(text,"exit")==0) {cout << "connexion terminé"<< endl; close(tcp_socket); break; }
  }

}

//cette fonction est appelé lorsqu'un noeud privé veut communiquer avec un noeud public
//fonctionnement semblable à public_connect_public
void  prive_connect_public()
  {

       cout << "je suis un noeud privé et je connecte vers un noeud public " << endl;
        int r1;
        int tcp_socket;
        bool sortie = true;
        tcp_socket = create_socketTCP();

        hostent * n_distant;
        in_addr * addressptr;
        n_distant = gethostbyname(ip_distant);
        if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
        addressptr = (in_addr *) n_distant -> h_addr;

        //j'attribue le socket à l'adresse ip local et au port_local-1
        local_info.sin_family = AF_INET;
        local_info.sin_addr.s_addr = htonl(INADDR_ANY);
        local_info.sin_port = htons(port_local_in-1);

        r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));

      //créer le sockaddr_in pour le noeud distant
      sockaddr_in n_distant_info;
      n_distant_info.sin_family = AF_INET;
      n_distant_info.sin_addr = *addressptr;
      n_distant_info.sin_port = htons(port_distant-1);//car la machine publique écoute sur son port_local-1

   //Se connecter au serveur
  r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
  if(r1<0){perror("connect");}
   else {

cout << "********************************************************************" << endl;
cout << "******************Debut de la communication TCP ********************" << endl;

            }

  char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
  cout << buf_tcp << endl;
  r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
  char text[100];
  cout << "\n\\" << endl;

  while(sortie)
  {
      cin >> text ;
      bzero(buf_tcp,sizeof(buf_tcp));
      strcpy(buf_tcp,text);
      r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
       if(strcmp(buf_tcp,"exit")==0)
        {
            cout <<"************************" << endl;
            cout << "connexion terminé" << endl;
            cout << "**********************" << endl;
            close(tcp_socket);
            break;
        }
  }

}

//cette fonction est appelé lorsqu'un noeud découvre qu'il est public et l'utilisateur demande
//de se mettre en écoute
void  public_waiting_tcp()
  {

      char buffer[100];
      cout << "debut du la phase  public waiting TCP" << endl;

      //créer le socket
      bool k = true;//pour afficher les données recues jusqu'à ce que je recois un exit
      int tcp_socket;
      tcp_socket = create_socketTCP();

       //préparer la structure d'adresse local
      local_info.sin_family = AF_INET;
      local_info.sin_addr.s_addr = htonl(INADDR_ANY);
      local_info.sin_port = htons(port_local_in-1);

        //préparer une structure pour l'adresse ip et le port de la machine distante
        struct sockaddr_in incoming_info;
        unsigned int socklen;
        char *who_is;
        socklen = sizeof(incoming_info);

      int b;
      //attribuer le socket à l'adresse ip et le port local
      b = bind(tcp_socket,(sockaddr *) &local_info,sizeof(local_info));
      if (b<0) { perror("bind"); exit (1);}

      //se mettre en écoute
      b = listen(tcp_socket,1);
      cout << "j'écoute sur le port: " << port_local_in-1 << endl;

      int a;
      int g;

      //accepter les communications entrantes
      a = accept(tcp_socket,(sockaddr *) &incoming_info,&socklen);
      if(a<0) {perror("accept");}
      else {
	who_is = inet_ntoa(incoming_info.sin_addr);
	printf("connexion accepté de %s:%d",who_is,htons(incoming_info.sin_port));
	cout << "\n\n" << endl;
	cout << "********************************************************************" << endl;
	cout << "******************Debut de la communication TCP ********************" << endl;

            }

            g = recv(a,buffer,sizeof(buffer),0);
            if(g<0) {perror("recv");}
            cout << buffer << endl;

    //afficher sur le terminal tout ce que je recois de la machine distante
    while(k==true)
    {
        bzero(buffer,sizeof(buffer));
        g = recv(a,buffer,sizeof(buffer),0);
        if(g<0) {perror("recv");}
        cout << buffer << endl;
        if(strcmp(buffer,"exit")==0)
        {
            cout <<"************************" << endl;
            cout << "connexion terminé" << endl;
            cout << "**********************" << endl;
            shutdown (tcp_socket,2);
            break;
        }
    }

  }

//cette fonction est appelé lorsqu'un noeud privé veut communiquer avec un noeud privé
//dans ce cas on appelle d'abord la fonction udp_punching_prive, pour communiquer d'abord en UDP
//et après on appelle la fonction tcp_connect pour réaliser la communication en TCP
void tcp_connect()
{
    int r1;//pour le bind, send et recv
    int tcp_socket;//déclarer le socket
    bool sortie = true;//pour arreter la communication quand je recois un exit
    tcp_socket = create_socketTCP();//créer le socket TCP

        //former la structure de l'adresse du noeud distant pour le socket
        hostent * n_distant;
        in_addr * addressptr;
        n_distant = gethostbyname(ip_distant);
        if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
        addressptr = (in_addr *) n_distant -> h_addr;

         //définir l'adresse et le port local pour les attribuer au socket
        local_info.sin_family = AF_INET;
        local_info.sin_addr.s_addr = htonl(INADDR_ANY);
        local_info.sin_port = htons(port_local_in+1);

        //attrivuer le socket à l'adresse ip et le port lcocal+1
        r1 = bind(tcp_socket,(sockaddr *) &local_info, sizeof(local_info));

      //créer le sockaddr_in pour le noeud distant
      sockaddr_in n_distant_info;
      n_distant_info.sin_family = AF_INET;
      n_distant_info.sin_addr = *addressptr;
      n_distant_info.sin_port = htons(port_distant+1);
      /*sockaddr_in test;
      int test_size = sizeof(test);*/

   //Se connecter à la machine distante qui a ouverts les trous TCP dans son NAT
  r1 = connect(tcp_socket,(sockaddr *)&n_distant_info,sizeof(n_distant_info));
  if(r1<0){perror("connect");}
  else
  {
cout << "******************************************************************" << endl;
cout << "************Debut de communication en TCP*************************" << endl;
cout << "\n" << endl;
  }
  char buf_tcp[] = "\n\ntcp connection de bout en bout\n\n";
  cout << buf_tcp << endl;
  //envoyer des données
  r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
  cout << "\n\\" << endl;
  char text[100];

  //tout ce que j'écris sur le terminal s'envoie à l'autre machine
  while(sortie)
  {

      cin >> text ;
      //on lis de la ligne du commande
      bzero(buf_tcp,sizeof(buf_tcp));
      strcpy(buf_tcp,text);
      bzero(text,sizeof(text));
      if(strcmp(buf_tcp,"exit")==0)
      {
          //si c'est exit, on ferme la connexion
          r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
cout << "******************************************************************" << endl;
cout << "************Fin de communication en TCP*************************" << endl;
cout << "\n" << endl;
shutdown(tcp_socket,2);
          break;

      }
      //sinon on envoie le texte écrit
      r1 = send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);

  }
}

//cette fonction est appelé lorsqu'une machine privé est recherché par une machine public
//la machine public se met en attente et la machine privé initie la connexion TCP
void  tcp_connect_public()
  {
      cout << "la phase lorsque le client privé est cherché par un client public" << endl;

      //récuperer les informations du noeud distant
      hostent * n_distant;
      in_addr * addressptr;
      n_distant = gethostbyname(ip_distant);
      if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
      addressptr = (in_addr *) n_distant -> h_addr;
      //définir l'adresse et le port distants pour les attribuer au socket
      sockaddr_in n_distant_info;
      n_distant_info.sin_family = AF_INET;
      n_distant_info.sin_addr = *addressptr;
      n_distant_info.sin_port = htons(port_distant-1);

      //créer le socket
      int tcp_socket;
      tcp_socket = create_socketTCP();
      //définir l'adresse et le port local pour les attribuer au socket
      local_info.sin_family = AF_INET;
      local_info.sin_addr.s_addr = htonl(INADDR_ANY);
      local_info.sin_port = htons(port_local_in-1);

      int b;
      bool sortie;
      char buf_tcp[100];
      char texte[100];
      //attrivuer le socket à l'adresse ip et le port lcocal-1
      b = bind(tcp_socket,(sockaddr *) &local_info,sizeof(local_info));
      if (b<0) { perror("bind"); exit (1);}
      //se connecter à la machine publique distante
      b = connect(tcp_socket,(sockaddr *) &n_distant_info,sizeof(n_distant_info));
      if(b<0){perror("connect");} 
	  else {cout << "****************connexion établie en TCP************** " << endl; }

      cout << "\n\\" << endl;

      while(sortie)
      {
          cin >> texte;
          bzero(buf_tcp,sizeof(buf_tcp));
          strcpy(buf_tcp,texte);

          b= send(tcp_socket,buf_tcp,sizeof(buf_tcp),0);
          if(strcmp(buf_tcp,"exit")==0)
          {
              cout << "connexion terminée" << endl;
             close (tcp_socket);
              break;
          }
      }

      }

//cette fonction est appelée lorsqu'une machine privée est recherché
//par une machine privée, la machine destinatrice appelle la fonction
//udp_punching pour ouvrir des trous udp et tcp dans son NAT afin de
//permettre au trafic venant de la station initiatrice de passer.
void  udp_punching()
  {
      int i = 2;//définir le nombre de requêtes UDP et TCP envoyés pour
                //ouvrir les trous dans le NAT (nombre = i*2 requêtes, soit
                //dans ce cas, 4 requêts UDP et 4 requêtes TCP )
      cout << "debut du la phase udp et tcp punching" << endl;

      //récuperer les informations du noeud distant

      hostent * n_distant;
      in_addr * addressptr;
      n_distant = gethostbyname(ip_distant);
      if (n_distant == NULL) {herror("gethostbyname failed"); exit(1); }
      addressptr = (in_addr *) n_distant -> h_addr;

      //créer le socket
      int udp_socket;
      udp_socket = create_socketUDP();
      int tcp_socket_2;
      tcp_socket_2 = create_socketTCP();

      //définir une structure d'adresse pour l'adresse ip local et le port local
      local_info.sin_family = AF_INET;
      local_info.sin_addr.s_addr = htonl(INADDR_ANY);
      local_info.sin_port = htons(port_local_in);
      //définir une structure d'adresse pour l'adresse ip local et le port local+1 $
      //pour la communication en TCP
      sockaddr_in local_2;
      local_2.sin_family = AF_INET;
      local_2.sin_addr.s_addr = htonl(INADDR_ANY);
      local_2.sin_port = htons(port_local_in+1);

      int b;
      //attribuer le socket UDP à l'adresse ip local et le port local
      b = bind(udp_socket,(sockaddr *) &local_info,sizeof(local_info));
      if (b<0) { perror("bind"); exit (1);}

      int c;
      //attribuer le socket TCP à l'adresse ip local et le port_local+1
      c= bind(tcp_socket_2,(sockaddr *) &local_2,sizeof(local_2));
      if (b<0) { perror("bind"); exit (1);}

      //créer le sockaddr_in pour le noeud distant
      //pour envoyer en UDP vers IPdistant: Pdistant
      sockaddr_in n_distant_info_udp;
      n_distant_info_udp.sin_family = AF_INET;
      n_distant_info_udp.sin_addr = *addressptr;
      n_distant_info_udp.sin_port = htons(port_distant);

      //pour envoyer en UDP vers IPdistant: Pdistant+1
      sockaddr_in n_distant_info_udp_2;
      n_distant_info_udp_2.sin_family = AF_INET;
      n_distant_info_udp_2.sin_addr = *addressptr;
      n_distant_info_udp_2.sin_port = htons(port_distant+1);

      //pour envoyer en TCP vers IPdistant: Pdistant
       sockaddr_in n_distant_info_tcp;
      n_distant_info_tcp.sin_family = AF_INET;
      n_distant_info_tcp.sin_addr = *addressptr;
      n_distant_info_tcp.sin_port = htons(port_distant);

      //pour envoyer en UDP vers IPdistant: Pdistant+1
      sockaddr_in n_distant_info_tcp_2;
      n_distant_info_tcp_2.sin_family = AF_INET;
      n_distant_info_tcp_2.sin_addr = *addressptr;
      n_distant_info_tcp_2.sin_port = htons(port_distant+1);

      char message1 [] = "punch_ my _ nat _UDP";
      char message2 [] = "communication établie en UDP";

      char buffer[100];
      //pour le traffic entrant
      struct sockaddr_in incoming_info;
      unsigned int socklen;
      socklen = sizeof(incoming_info);

    //envoyer des requêtes UDP et TCP pour ouvrir les trous dans le NAT
      while(i>0)
      {

b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info_udp,sizeof(n_distant_info_udp));
if (b < 0) {perror("sendto"); exit (1);}
printf("UDP: premier message envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_udp.sin_addr),port_distant);

b = sendto(udp_socket,message1,strlen(message1),MSG_EOR,(sockaddr *)&n_distant_info_udp_2,sizeof(n_distant_info_udp_2));
if (b < 0) {perror("sendto"); exit (1);}
printf("UDP: deuxième message envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_udp_2.sin_addr),port_distant+1);

cout << "\n" << endl;

c = connect(tcp_socket_2,(sockaddr *)&n_distant_info_tcp,sizeof(n_distant_info_tcp));
printf("TCP:  SYN envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_tcp.sin_addr),port_distant);
	
c = connect(tcp_socket_2,(sockaddr *)&n_distant_info_tcp_2,sizeof(n_distant_info_tcp_2));
printf("TCP:  SYN envoyé à destination de %s : %d\n ",inet_ntoa(n_distant_info_tcp_2.sin_addr),port_distant+1);

cout << "\n" << endl;

i=i-1;

      }

cout << "**************************************************************************" << endl;

      //attendre une réponse en UDP

       b = recvfrom(udp_socket,&buffer,sizeof(buffer)-1,0,(sockaddr *)&incoming_info,&socklen);
       if(b<0) { cout<< "rien recu en UDP" << endl; }
       else{
cout << "communication établie en UDP avec " <<inet_ntoa(incoming_info.sin_addr)<< ":"<<htons(incoming_info.sin_port)<<  endl;

cout << "Données recues en UDP" << endl;
cout << buffer << endl;
cout << "\n" << endl;

            //répondre en UDP
	b = sendto(udp_socket,message2,strlen(message2),MSG_EOR,(sockaddr *)&incoming_info,socklen);
	cout << "Donnée envoyé en UDP: " << endl;
	cout << message2 << endl;
	cout << "\n" << endl;

       }

        cout << "Fin de la communication en UDP" << endl;

cout << "**************************************************************************" << endl;
        //fermer la connexion UDP
        close(udp_socket);

        cout << "\n" << endl;
        cout << "**************************************" << endl;
        cout << "Début de la communication en TCP" << endl;
         cout << "**************************************" << endl;
        cout << "\n" << endl;
        //la machine écoute en TCP sur son port_local+1
        //la machine a déjà envoyé des requêtes de ce port source
        c = listen(tcp_socket_2,1);

        cout << "j'écoute sur le port " << port_local_in+1 << endl;

        bool sortie = true;
        char buf_tcp[99];
        sockaddr_in client;
        unsigned int client_size = sizeof(client);
        char * who_is;
        int g;
        int a;

        //accepter la connexion de la machine distante
        a = accept(tcp_socket_2,(sockaddr *) &client,&client_size);
        if(a < 0) {perror("accept"); exit(1);}

        who_is = inet_ntoa(client.sin_addr);
        printf("[connexion  accepté de %s : %d]\n", who_is,htons(client.sin_port));

        //pour recevoir les données textes de la machine distante
        while(sortie)
        {

        bzero(buf_tcp,sizeof(buf_tcp));
       g = recv(a,buf_tcp,sizeof(buf_tcp),0);
       if(a<0) {perror("recv"); exit(1);}
       //j'affiche tous jusqu'à ce que je recois un exit
       cout << buf_tcp << endl;
       if(strcmp(buf_tcp,"exit")==0) {

            cout << "**************************************" << endl;
            cout << "Fin de la communication TCP"<< endl;
            cout << "**************************************" << endl;
            close(a);//fermeture de la connexion TCP
            break;
           }
       }

      }
	  
	  //fin fichier p2pnat.cpp

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.