import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.SocketException; import java.net.UnknownHostException; import java.util.HashMap; /** * @author nthrasher * * An implementation of a generic NODE */ public class NodeImpl implements Node { private int port = 11777; private MulticastHandler mHandler; private UDPHandler udpHandler; private HashMap nodes = new HashMap(); private String name; private InetSocketAddress address; public NodeImpl(String name, InetSocketAddress address) { this.name = name; this.address = address; this.port = address.getPort(); udpHandler = new UDPHandler(); mHandler = new MulticastHandler(); broadcastConnectionInfo(); } /** * broadcasts udp connection info. */ public void broadcastConnectionInfo() { mHandler.sendInfo(Node.REG, name, address); } /** * stores connection information from other nodes */ public void receiveConnectionInfo(String name, InetSocketAddress address) { //store info if not already stored or if the info isn't me if (!nodes.containsKey(name) && !name.equals(this.name)) { System.out.println("Storing node: "+name+"'s information."); nodes.put(name, address); } else { System.out.println("["+name+"] already stored"); } } /** * returns connection info about other nodes by name */ public InetSocketAddress getConnectionInfo(String name) { return (InetSocketAddress) nodes.get(name); } /** * Sends a packet. * The packet contains it's own routing information. */ public void sendPacket(Packet packet) { udpHandler.send(packet); } /** * Handles packets which are received by udp connection. * * In this case, we assume they are strings and * just print them out to the command line */ public void receivePacket(byte[] payload) { System.out.println("["+name+"] PacketReceived: "+new String(trimBuffer(payload))); } // helper method to trim out the useful string. private byte[] trimBuffer(byte[] bs) { byte[] temp = null; for (int i=0; i < bs.length; i++) { if (bs[i] == '\0') { temp = new byte[i]; break; } } System.arraycopy(bs, 0, temp, 0, temp.length); return temp; } public void ping() { mHandler.ping(); } public void close() { mHandler.sendInfo(Node.DEREG, name, address); mHandler.closeConnection(); udpHandler.closeConnection(); } /** * Class which handles udp connection */ class UDPHandler implements Runnable { private DatagramSocket socket; UDPHandler() { try { socket = new DatagramSocket(address); } catch (SocketException e) { e.printStackTrace(); } Thread t = new Thread(this); t.start(); } void send(Packet packet) { try { DatagramPacket msg = new DatagramPacket(packet.getPayload(), packet.getPayload().length, packet.getDest()); socket.send(msg); } catch (SocketException e) { } catch (IOException e) { } } void closeConnection() { socket.close(); } public void run() { try { while (true) { byte[] buf = new byte[1000]; DatagramPacket recv = new DatagramPacket(buf, buf.length); socket.receive(recv); receivePacket(recv.getData()); } } catch (IOException e) {//closeConnection() was probably called } } } /** * Class which handles multicast connection. */ class MulticastHandler implements Runnable { private InetAddress group; private MulticastSocket socket; private DataInputStream inputStream; byte[] buf = new byte[1000]; MulticastHandler() { connect(); Thread t = new Thread(this); t.start(); } private void connect() { try { group = InetAddress.getByName("228.5.6.7"); socket = new MulticastSocket(6789); socket.joinGroup(group); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * @see java.lang.Runnable#run() */ public void run() { byte[] tbuf = null; try { while (true) { // get their responses! DatagramPacket recv = new DatagramPacket(buf, buf.length); socket.receive(recv); inputStream = new DataInputStream(new ByteArrayInputStream(recv.getData())); int code = inputStream.readInt(); if (code == Node.PING) { broadcastConnectionInfo(); } else if (code == Node.REG) { String name = inputStream.readUTF(); String ip = inputStream.readUTF(); int port = inputStream.readInt(); InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(ip), port); receiveConnectionInfo(name, address); } else if (code == Node.DEREG) { System.out.println("Removing node: "+name); nodes.remove(name); } } } catch (IOException e) {//closeConnection() was probably called } } void closeConnection() { try { socket.leaveGroup(group); } catch (IOException e) { e.printStackTrace(); } socket.close(); } public void ping() { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(bos); try { outputStream.writeInt(Node.PING); } catch (IOException e) { e.printStackTrace(); } DatagramPacket packet = new DatagramPacket(bos.toByteArray(), bos.toByteArray().length, group, 6789); try { socket.send(packet); } catch (IOException e1) { e1.printStackTrace(); } } public void sendInfo(int type, String name, InetSocketAddress address) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(bos); try { outputStream.writeInt(type); outputStream.writeUTF(name); outputStream.writeUTF(address.getHostName()); outputStream.writeInt(address.getPort()); } catch (IOException e) { e.printStackTrace(); } DatagramPacket packet = new DatagramPacket(bos.toByteArray(), bos.toByteArray().length, group, 6789); try { socket.send(packet); } catch (IOException e1) { e1.printStackTrace(); } } } }