package chat; import java.net.*; import javax.swing.*; import java.awt.*; import java.util.List; import java.awt.event.*; import java.io.*; import java.util.*; import chat.User; import chat.Message; class OutdoorListenerThread extends Thread { User user; JTextArea displayArea; JTextArea knownUsersPanel; List known_users; List dest_sockets; List outdoor_dest_sockets; int portNumber; OutdoorListenerThread(User in_user, List in_known_users, List in_dest_sockets, List in_outdoor_dest_sockets, JTextArea in_displayArea, JTextArea in_knownUsersPanel) { user = in_user; known_users = in_known_users; dest_sockets = in_dest_sockets; outdoor_dest_sockets = in_outdoor_dest_sockets; displayArea = in_displayArea; knownUsersPanel = in_knownUsersPanel; portNumber = 2344; } public void run() { boolean exit = false; boolean accepted = true; byte[] buffer = new byte[100]; String username; String response = ""; byte[] responseBytes; try { while(!exit) { try { System.out.println("Waiting for connection request"); ServerSocket servSocket = new ServerSocket(1234); Socket link = servSocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(link.getInputStream())); PrintWriter out = new PrintWriter(link.getOutputStream(), true); username = in.readLine(); System.out.println("Received a request from " + username + "@" + link.getRemoteSocketAddress().toString()); response = ""; for(User u:known_users) { response += u.getName() + " "; } response = response.trim(); response += ";"; for(Socket s:dest_sockets) { response += s.getInetAddress().getHostAddress() + " "; } response = response.trim(); response += ";" + (portNumber+1); out.println(response); accepted = true; for(User a:known_users) { accepted = accepted && (!username.equals(a.getName())); } if(accepted) { portNumber++; Socket s = (new ServerSocket(portNumber)).accept(); (new ReceiveThread(user, s, displayArea, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start(); outdoor_dest_sockets.add(s); known_users.add(new User(username)); Collections.sort(known_users); displayArea.append(username + " has joined the chat.\n"); displayArea.setCaretPosition(displayArea.getDocument().getLength()); knownUsersPanel.setText(""); knownUsersPanel.append("Online:\n"); for(User a:known_users) { knownUsersPanel.append(" " + a.getName() + " \n"); } } } catch(SocketTimeoutException e) {} } } catch(Exception e) { e.printStackTrace(); System.out.println(e.getMessage()); } } } class ReceiveThread extends Thread { User user; Socket socket; JTextArea displayArea; JTextArea knownUsersPanel; Boolean isOutdoor; List known_users; List dest_sockets; List outdoor_dest_sockets; ReceiveThread(User in_user, Socket in_socket, JTextArea in_displayArea, List in_known_users, JTextArea in_knownUsersPanel, List in_dest_sockets, List in_outdoor_dest_sockets, Boolean in_isOutdoor) { user = in_user; socket = in_socket; displayArea = in_displayArea; knownUsersPanel = in_knownUsersPanel; known_users = in_known_users; dest_sockets = in_dest_sockets; outdoor_dest_sockets = in_outdoor_dest_sockets; isOutdoor = in_isOutdoor; } public void run() { boolean exit = false; try { while(!exit) { ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); Message message = (Message) in.readObject(); if(message.getText() != null) { displayArea.append(message.getAuthor() + " : " + message.getText() + "\n"); } else { displayArea.append(message.getAuthor() + " has left the chat.\n"); for(int i = 0;i < known_users.size();i ++) { if (known_users.get(i).getName().equals(message.getAuthor())) { known_users.remove(i); break; //System.out.println("Removing " + message.getAuthor()); } } knownUsersPanel.setText(""); knownUsersPanel.append("Online:\n"); for(User u:known_users) { knownUsersPanel.append(" " + u.getName() + " \n"); } if(!message.getAuthor().equals(user.getName())) { socket.close(); if(!isOutdoor) dest_sockets.remove(socket); else outdoor_dest_sockets.remove(socket); } exit = true; } displayArea.setCaretPosition(displayArea.getDocument().getLength()); if(isOutdoor) { for(Socket s:dest_sockets) { try { ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); out.writeObject(message); } catch(IOException e){} } } for(Socket s:outdoor_dest_sockets) { try { ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); out.writeObject(message); } catch(IOException e){} } } } catch(EOFException e) {} catch(Exception e) { e.printStackTrace(); } } } class ConnectionListenerThread extends Thread { User user; JTextArea displayArea; JTextArea knownUsersPanel; List known_users; List dest_sockets; List outdoor_dest_sockets; int portNumber; ConnectionListenerThread(User in_user, List in_known_users, List in_dest_sockets, List in_outdoor_dest_sockets, JTextArea in_displayArea, JTextArea in_knownUsersPanel, int in_portNumber) { user = in_user; known_users = in_known_users; dest_sockets = in_dest_sockets; outdoor_dest_sockets = in_outdoor_dest_sockets; displayArea = in_displayArea; knownUsersPanel = in_knownUsersPanel; portNumber = in_portNumber; } public void run() { boolean exit = false; boolean accepted = true; byte[] buffer = new byte[100]; DatagramPacket request = new DatagramPacket(buffer, buffer.length); DatagramPacket responsePacket; DatagramSocket requestSocket; DatagramSocket responseSocket; String username; String response = ""; byte[] responseBytes; try { requestSocket = new DatagramSocket(1234); responseSocket = new DatagramSocket(); while(!exit) { try { System.out.println("Waiting for connection request"); requestSocket.receive(request); username = new String(request.getData(), 0, request.getLength()); InetAddress clientAddress= request.getAddress(); System.out.println("Received a request from " + username + "@" + clientAddress.getHostAddress()); response = ""; for(User u:known_users) { response += u.getName() + " "; } response = response.trim(); response += ";"; for(Socket s:dest_sockets) { response += s.getInetAddress().getHostAddress() + " "; } response = response.trim(); response += ";" + (portNumber+1); System.out.println("Response :" + response); responseBytes = response.getBytes(); responsePacket = new DatagramPacket(responseBytes, responseBytes.length, clientAddress, 1337); responseSocket.send(responsePacket); accepted = true; for(User a:known_users) { accepted = accepted && (!username.equals(a.getName())); } if(accepted) { portNumber++; Socket s = (new ServerSocket(portNumber)).accept(); (new ReceiveThread(user, s, displayArea, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start(); dest_sockets.add(s); known_users.add(new User(username)); Collections.sort(known_users); displayArea.append(username + " has joined the chat.\n"); displayArea.setCaretPosition(displayArea.getDocument().getLength()); knownUsersPanel.setText(""); knownUsersPanel.append("Online:\n"); for(User a:known_users) { knownUsersPanel.append(" " + a.getName() + " \n"); } } } catch(SocketTimeoutException e) {} } } catch(Exception e) { e.printStackTrace(); System.out.println(e.getMessage()); } } } class ListenerStartThread extends Thread { ServerSocket s; List dest_sockets; ListenerStartThread(ServerSocket in_s, List in_dest_sockets) { s = in_s; dest_sockets = in_dest_sockets; } public void run() { try { dest_sockets.add(s.accept()); } catch(IOException e) {} } } public class NetworkClient { private User user; private List known_users; private List dest_sockets; private List outdoor_dest_sockets; private JTextArea chatText; private JTextArea knownUsersPanel; static String getLocalIP() { String ip = ""; try(final DatagramSocket socket = new DatagramSocket()){ socket.connect(InetAddress.getByName("8.8.8.8"), 10002); ip = socket.getLocalAddress().getHostAddress(); } catch(Exception e) { System.out.println("niiiiiiiikkk"); } return ip; } NetworkClient(JTextArea in_chatText, JTextArea in_knownUsersPanel) { user = new User(""); chatText = in_chatText; knownUsersPanel = in_knownUsersPanel; known_users = new ArrayList(); dest_sockets = new ArrayList(); outdoor_dest_sockets = new ArrayList(); } boolean connect(String username, Boolean outdoor, String destinationIP) { boolean nameAvailable = true; boolean connected = false; DatagramSocket connectionSocket; DatagramSocket userListSocket; DatagramPacket connectionRequest; DatagramPacket responsePacket; String[] usernameList; String[] addressList; int portNumber = 1237; byte[] buffer1 = new byte[20000]; if(username == null || username.compareTo("") == 0) return false; try { try { if(!outdoor) { connectionSocket = new DatagramSocket(); userListSocket = new DatagramSocket(1337); userListSocket.setSoTimeout(500); connectionRequest = new DatagramPacket(username.getBytes(), username.length(), InetAddress.getByName(destinationIP), 1234); /*l'adresse de broadcast est hardcodée ici pour tester avec Hamachi, il faut la remplacer par celle du réseau local virtuel*/ System.out.println("Sending connection request"); connectionSocket.send(connectionRequest); responsePacket = new DatagramPacket(buffer1, buffer1.length); System.out.println("Waiting for reply"); userListSocket.receive(responsePacket); System.out.println("Received a reply from " + responsePacket.getAddress().getHostAddress()); String[] response = new String(responsePacket.getData()).trim().split(";"); usernameList = response[0].split(" "); addressList = response[1].split(" "); portNumber = Integer.parseInt(response[2]); connectionSocket.close(); userListSocket.close(); } else { Socket requestSocket = new Socket(destinationIP, 1234); BufferedReader in = new BufferedReader(new InputStreamReader(requestSocket.getInputStream())); PrintWriter out = new PrintWriter(requestSocket.getOutputStream(), true); out.println(username); String[] response = in.readLine().split(";"); usernameList = response[0].split(" "); addressList = new String[0]; portNumber = Integer.parseInt(response[2]); requestSocket.close(); } for(String u:usernameList) { nameAvailable = nameAvailable && (!username.equals(u)); } if(nameAvailable) { System.out.println(usernameList.length + " users currently connected"); for(String u:usernameList) { known_users.add(new User (u)); } for(String a:addressList) { Socket s = new Socket(a, portNumber); dest_sockets.add(s); (new ReceiveThread(user, s, chatText, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start(); } Collections.sort(known_users); connected = true; } } catch(SocketTimeoutException e) //Si on est tout seul sur le réseau (on ne reçoit aucune réponse) { System.out.println("Reply timed out"); connected = true; } } catch (SocketException e2) { e2.printStackTrace(); } catch (Exception e3) { e3.printStackTrace(); } if(connected) { if(!outdoor) { (new ConnectionListenerThread(user, known_users, dest_sockets, outdoor_dest_sockets, chatText, knownUsersPanel, portNumber)).start(); (new OutdoorListenerThread(user, known_users, dest_sockets, outdoor_dest_sockets, chatText, knownUsersPanel)).start(); try { ServerSocket s1 = new ServerSocket(portNumber); (new ListenerStartThread(s1, dest_sockets)).start(); Socket s2 = new Socket(getLocalIP(), portNumber); System.out.println(getLocalIP()); /*Attention, getLocalIP ne marche que sur un même réseau physique * pour tester avec Hamachi, il faut hardcoder les IP */ (new ReceiveThread(user, s2, chatText, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start(); } catch(IOException e) { e.printStackTrace(); } } else { try { Socket s = new Socket(destinationIP, portNumber); dest_sockets.add(s); } catch(IOException e) { e.printStackTrace(); } } user.setName(username); known_users.add(new User(username)); Collections.sort(known_users); chatText.append(username + " has joined the chat.\n"); chatText.setCaretPosition(chatText.getDocument().getLength()); knownUsersPanel.setText(""); knownUsersPanel.append(" Online :\n"); for(User a:known_users) { knownUsersPanel.append(" " + a.getName() + " \n"); } } return connected; } void send (String message) { System.out.println("Sending message"); System.out.println("Indoor users:"); for(Socket s:dest_sockets) { try { System.out.println(s.getInetAddress().getHostAddress() + ": local port " + s.getLocalPort() + ", remote port " + s.getPort()); ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); out.writeObject(new Message(user.getName(), message)); } catch(IOException e){} } System.out.println("Outdoor users:"); for(Socket s:outdoor_dest_sockets) { try { System.out.println(s.getInetAddress().getHostAddress() + ": local port " + s.getLocalPort() + ", remote port " + s.getPort()); ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); out.writeObject(new Message(user.getName(), message)); } catch(IOException e){} } } void disconnect() { send(null); try { Thread.sleep(1000); } catch(InterruptedException e) {} for(Socket s:dest_sockets) { try { s.close(); } catch(IOException e){} } } }