package src.Protocoles; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.Inet4Address; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import src.Controller.*; /** *

* Classe representant les echanges UDP entre utilisateurs. *

*/ public class UDPEchange { private static Boolean Connecte = true; // True si l'utilisateur peut se connecter avec ce nom d'utilisateur , False sinon /** * Getter * @return le boolean connecte (True s'il peut se connecter avec ce nom d'utilisateur , False sinon) */ public static Boolean getConnecte() { return Connecte; } /** * Setter * @param value La nouvelle valeur du boolean de connexion */ public static void setConnecte(Boolean value) { Connecte = value ; } private static Boolean PseudoValide = true; // True si l'utilisateur a (ou demande) un pseudo valide , False sinon /** * Getter * @return le boolean PseudoValide (True s'il peut utiliser ce pseudo , False sinon) */ public static Boolean getPseudoValide() { return PseudoValide; } /** * Setter * @param value La nouvelle valeur du boolean concernant le pseudo valide */ public static void setPseudoValide(Boolean value) { PseudoValide = value ; } public static InetAddress getCurrentIp() { try { Enumeration networkInterfaces = NetworkInterface .getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { NetworkInterface ni = (NetworkInterface) networkInterfaces .nextElement(); Enumeration nias = ni.getInetAddresses(); while(nias.hasMoreElements()) { InetAddress ia= (InetAddress) nias.nextElement(); if (!ia.isLinkLocalAddress() && !ia.isLoopbackAddress() && ia instanceof Inet4Address) { return ia; } } } } catch (Exception e) { System.out.println("unable to get current IP " + e.getMessage()); } return null; } /** *

* Méthode permettant d'envoyer un message à tout les utilisateurs * a l'aide du protocole UDP *

* @param broadcastMessage correspond au message a transmettre aux utilisateurs */ public static void EnvoiBroadcast(String broadcastMessage) throws IOException { int port = 1234 ; // Envoie en broadcast à tous les utilsateurs for (InetAddress broadcastAddr : listAllBroadcastAddresses()) { DatagramSocket socket = new DatagramSocket(); socket.setBroadcast(true); byte[]buffer = broadcastMessage.getBytes(); DatagramPacket packet = new DatagramPacket( buffer, buffer.length, broadcastAddr,port); socket.send(packet); socket.close(); System.out.println("Broadcast sent with address " + broadcastAddr.toString()); System.out.println("***********Message envoye***********"); System.out.println("Dest Ip: " + broadcastAddr.toString()); System.out.println("Dest port: " + String.valueOf(port)); System.out.println("Contenu: "); System.out.println(broadcastMessage); System.out.println("************************************"); } } /** *

* Methode permettant la reception de messages d'utilisateurs * a l'aide du protocole UDP *

* @param app L'application de chat de l'utilisateur qui receptionne le message */ public static void ecouteUDP(ChatApp app) { DatagramSocket socket = null; ExecutorService exec = Executors.newFixedThreadPool(1000); try { socket = new DatagramSocket(1234); } catch (SocketException e1) { e1.printStackTrace(); } byte buffer[] = new byte[1024]; System.out.println("Ecoute sur le port: 1234"); while(true) { DatagramPacket data = new DatagramPacket(buffer,buffer.length); try { socket.receive(data); } catch (IOException e) { e.printStackTrace(); } // Un thread est lance à chaque reception d'un message System.out.println("Message recu!"); exec.submit(new RunnerUDP(data,app)); } } /** *

* Methode permettant d'envoyer un message a utilisateur en particulier * a l'aide du protocole UDP *

* @param Adress l'addresse de l'utilisateur * @param Message correspond au message à transmettre a l'utilisateur */ public static void envoiUnicast( InetAddress Adress , String Message ) throws IOException { DatagramSocket socket = new DatagramSocket(); byte[]buffer = Message.getBytes(); DatagramPacket packet = new DatagramPacket( buffer, buffer.length, Adress, 1234 ); socket.send(packet); socket.close(); System.out.println("***********Message envoye***********"); System.out.println("Dest Ip: " + Adress.toString()); System.out.println("Dest port: " + String.valueOf(1234)); System.out.println("Contenu: "); System.out.println(Message); System.out.println("************************************"); } /** *

* Methode permettant de recuperer la liste des adresses de broadcast, chacune associer à une interface de la machine *

*/ static List listAllBroadcastAddresses() throws SocketException { List broadcastList = new ArrayList<>(); Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface networkInterface = interfaces.nextElement(); if (networkInterface.isLoopback() || !networkInterface.isUp()) { continue; } networkInterface.getInterfaceAddresses().stream() .map(a -> a.getBroadcast()) .filter(Objects::nonNull) .forEach(broadcastList::add); } return broadcastList; } } /** *

* Classe implementant l'interface Runnable. * Contient les traitements a executer dans un thread lancer par des methodes de la class UDPEchange *

*/ class RunnerUDP implements Runnable { final DatagramPacket data ; ChatApp app ; public RunnerUDP(DatagramPacket data, ChatApp app) { this.data= data; this.app = app ; } /** *

* Methode qui redefinie les traitements qui seront executes dans le thread: * Met à jour la liste des utilisateurs actifs *

* */ @Override public void run() { System.out.println("Thread started"); String received = new String(data.getData(), 0, data.getLength()); System.out.println("***********Message recu***********"); System.out.println(received); System.out.println("**********************************"); String Type = received.split("\n")[0]; //**************************************************************************************************** //**************************************************************************************************** //****************************************Demande de connexion**************************************** //**************************************************************************************************** //**************************************** if (Type.equals("Connexion")) { // un utilisateur vient d'arriver sur le reseau System.out.println("Reception d'une demande de connexion"); Utilisateur u = Utilisateur.stringToUtilisateur(received.split("\n")[1]); if (! u.equals(this.app.getMe())) { // On envoit en broadcast mais on ne souhaite pas recevoir de message de nous même String reponse = "Reponse Connexion\n"; if (!( app.getActifUsers() ).verifierUnicite(u.getPseudo())) { System.out.println("Pseudo deja present dans la liste"); reponse += "false\n"; } else { System.out.println("Ajout d'un nouvel utilisateur dans la liste des Utilisateurs"); ( app.getActifUsers() ).addList(u); reponse += "true\n"; } reponse += app.getMe().toString(); try { UDPEchange.envoiUnicast(u.getIp(),reponse); }catch(IOException e) { System.out.println("Echec de l'envoi du message"); } ( app.getActifUsers() ).afficherListeUtilisateurs(); } } //******************************************************************************************************* //******************************************************************************************************* //****************************************Reponse d'une connexion**************************************** //******************************************************************************************************* //******************************************************************************************************* if (Type.equals("Reponse Connexion")) { // Un utilisateur te repond suite à ta demande de connexion if((received.split("\n")[1]).equals("true")) { Utilisateur u = Utilisateur.stringToUtilisateur(received.split("\n")[2]); app.getActifUsers().addList(u); app.getActifUsers().afficherListeUtilisateurs(); } else { System.out.println("Pseudo deja pris"); UDPEchange.setConnecte(false); } } //******************************************************************************************************************* //******************************************************************************************************************* //****************************************Demande de modification d'un pseudo**************************************** //******************************************************************************************************************* //******************************************************************************************************************* if (Type.equals("Demande Modification Pseudo")) { Utilisateur Source = Utilisateur.stringToUtilisateur(received.split("\n")[1]); if (! Source.equals(this.app.getMe())) { // On envoit en broadcast mais on ne souhaite pas recevoir de message de nous même String nouveau = received.split("\n")[2] ; String Message = ""; if(( app.getActifUsers() ).verifierUnicite(nouveau)) { Message = "Bon Choix Pseudo\n" + nouveau ; } else { Message = "Mauvais Choix Pseudo\n" ; } System.out.println(Message); try { UDPEchange.envoiUnicast(Source.getIp(),Message); } catch (IOException e) { e.printStackTrace(); } } } //************************************************************************************************************ //************************************************************************************************************ //**************************************** Modification pseudo reussi **************************************** //************************************************************************************************************ //************************************************************************************************************ if (Type.equals("Modification pseudo reussi")) { Utilisateur Source = Utilisateur.stringToUtilisateur(received.split("\n")[1]); if (! Source.equals(this.app.getMe())) { // On envoit en broadcast mais on ne souhaite pas recevoir de message de nous même String nouveau = received.split("\n")[2] ; if(app.getActifUsers().appartient(Source)) { // On verifie d'abord que Source appartient bien a la liste des utilisateurs actifs app.getActifUsers().modifierList(Source.getPseudo(), nouveau); } { // Suite a une perte d'un message lors d'une connexion l'utilisateur Source n'apparait pas dans la liste app.getActifUsers().addList(Source); } } } //********************************************************************************************************* //********************************************************************************************************* //****************************************Mauvais choix d'un pseudo**************************************** //********************************************************************************************************* //********************************************************************************************************* if (Type.equals("Mauvais Choix Pseudo")) { System.out.println("Ce choix de pseudo est déjà pris il te faut en choisir un autre"); UDPEchange.setPseudoValide(false); } //****************************************************************************************************************** //****************************************************************************************************************** //****************************************Bon choix d'un pseudo***************************************************** //****************************************************************************************************************** //****************************************************************************************************************** if (Type.equals("Bon Choix Pseudo")) { // Il n'y a rien a faire ici } //********************************************************************************************************* //********************************************************************************************************* //****************************************Demande d'une deconnexion**************************************** //********************************************************************************************************* //********************************************************************************************************* if (Type.equals("Deconnexion")) { ( app.getActifUsers() ).supprimerList(Utilisateur.stringToUtilisateur(received.split("\n")[1])); } } }