/** * * Channel * * No, not the perfume. * * A Channel represents one multicast address, and a series of * clients that are interested in that address. A channel listens * on a specific multicast address and forwards the traffic, via * a unicast bridge, to one or more clients. Clients subscribe and * unsubscribe themselves to channels. This is an example of the * Observer pattern, GoF p. 293. * * This requires the use of JDK 1.2 for various collection datastructures. * * Author: Don McGregor * Date: 2/19/99 * * */ package mil.navy.nps.bridge; import java.io.*; import java.net.*; import java.util.*; public class Channel implements Runnable { InetAddress mcastAddress; // Address we listen on int port; // port we listen on MulticastSocket sock; // Socket we use to read & send HashSet clients; // List of clients we send to /** * Constructor; takes a multicast address and a port to listen on */ public Channel(String pMcastAddress, int pPort) { clients = new HashSet(); // List of people we forward to try { mcastAddress = InetAddress.getByName(pMcastAddress); port = pPort; } catch(UnknownHostException unkhe) { System.out.println("unknown host " + unkhe); } } /** * hascode, just the hashcode of the mcast address. Close enough. * Note that this is not the same as equality... */ public int hashCode() { return mcastAddress.hashCode(); } /** * A Channel object is equal to another channel object if it has * the same multicast address and port to listen on. */ public boolean equals(Object pObject) { Channel aChannel; if(!(pObject instanceof Channel)) return false; aChannel = (Channel)pObject; if((mcastAddress.equals(aChannel.mcastAddress)) && (port == aChannel.port)) { return true; } return false; } /** * Subscribe one client. This client will receive, via unicast packets, * the packets that arrive on them multicast address. (see observer pattern) */ public void subscribeClient(Client pClient) { clients.add(pClient); } /** * Unsubscribe a client; this client will no longer receive packets * that arrive on this mcast address. (see observer pattern) */ public void unsubscribeClient(Client pClient) { clients.remove(pClient); } /** * Implementation of the Runnable interface. Loops, reading from * the multicast socket and forwarding to the list of clients. */ public void run() { boolean clientsActive = true; // Create the socket and join the multicast group. try { sock = new MulticastSocket(port); sock.joinGroup(mcastAddress); System.out.println("Joined group " + mcastAddress.getHostAddress()); } catch(SocketException se) { System.out.println("Socket exception " + se); } catch(IOException ioe) { System.out.println("IO exception on creating socket " + ioe); } // As long as the clients are active, loop, reading from multicast // and forwarding to the list of clients. while(clientsActive) { DatagramPacket packet; byte buf[] = new byte[1500]; Iterator it; //System.out.println("looping to forward packets"); packet = new DatagramPacket(buf, buf.length); try { sock.receive(packet); //System.out.println("got a packet"); // Send a copy to every client it = clients.iterator(); while(it.hasNext()) { Client aClient = (Client)it.next(); // Reset the recieved packet to have the designated destination, then // send it. packet.setAddress(aClient.clientAddress); packet.setPort(aClient.port); sock.send(packet); //System.out.println("forwarded packet"); } // No more clients, perhaps because they all timed out? Stop // the run and exit from the channel. if(clients.isEmpty()) { clientsActive = false; // Remove us from the list of channels MulticastTunnelServer.getInstance(0).removeChannel(this); } } catch(IOException ioe) { System.out.println("IO exception on receive " + ioe); } } // end of while loop // Close down socket nicely sock.close(); } }