package context.arch.comm.protocol; import java.net.MulticastSocket; import java.net.DatagramPacket; import java.net.InetAddress; import java.util.logging.Level; import java.util.logging.Logger; import java.io.IOException; /** * This class implements a threaded server - client socket that accepts UDP * multicast packets. * It does nothing with the UDP packets themselves but can be subclassed * to do real work. Whenever it receives data, it clones itself. The original * class listens for more new incoming packets while the clone handles the received * data. * * - Information about TTL (Time To Live) - * You can specify the TTL for multicast packet. The TTL values are : * 0 : transmitter * 1 : local network * 16 : site * 32 : county * 48 : country * 64 : continent * 128 : world * * @see java.lang.Runnable * @see java.lang.Cloneable */ public class MulticastUDPSocket implements Runnable, Cloneable, MulticastConstants { private static final Logger LOGGER = Logger.getLogger(MulticastUDPSocket.class.getName()); static {LOGGER.setLevel(Level.WARNING);} /** * Debug flag. Set to true to see debug messages. */ public static boolean DEBUG = false; /** * The TTL value */ //private static byte ttl; // why would it have been static? private int ttl; /** * Multicast socket */ private MulticastSocket serverSocket; private Thread runner = null; /** * Data received */ private DatagramPacket data = null; /** * Number of the used multicast port */ private int portNumber = MulticastConstants.DEFAULT_MULTICAST_PORT; /** * Address of the used multicast address */ private String groupAddress = MulticastConstants.DEFAULT_MULTICAST_ADDRESS; /** * Group */ private InetAddress group; @SuppressWarnings("unused") private MulticastUDPSocket parentSocket = null; // what was this for?? /** * Default constructor for MulticastUDPSocket, with the default port. * The multicast address and port must be changed in the MulticastConstants class * @see ... */ public MulticastUDPSocket() { this(TTL_SITE); } public MulticastUDPSocket(int ttlValue){ this.ttl = ttlValue; } /** * Starts a ServerSocket and a thread with this MulticastUDPSocket * as the Runnable. */ public void start() { if (runner == null) { try { LOGGER.info("Multicast service : port " + portNumber + " group "+ groupAddress ); group = InetAddress.getByName(groupAddress); serverSocket = new MulticastSocket(portNumber); //at least under Windows with multiple network interfaces, the multicast socket //sometimes gets confused and doesn't receive packets. Explicitly binding //to the network interface of InetAddress.getLocalHost seems to resolve the problem serverSocket.setInterface(InetAddress.getLocalHost()); // Joins the group serverSocket.joinGroup(group); //serverSocket.setTTL(ttl); // Deprecated serverSocket.setTimeToLive(ttl); runner = new Thread(this); runner.start(); } catch (IOException ioe) { System.out.println("MulticastUDPSocket init error: "+ioe + " on port number "+portNumber + " with group address " + groupAddress); } } } /** * Stops the original thread (just the original?) running and closes the socket. */ public void stopServer() { if (serverSocket != null) { runner = null; try { //Leave the group serverSocket.leaveGroup(group); serverSocket.close(); serverSocket = null; try { Thread.sleep(5000l); } catch (InterruptedException ie) { System.out.println("" + ie); } } catch (IOException ioe){ System.out.println("MulticastUDPSocket run IOexception: " +ioe); } } else { System.out.println("stopServer : in a child thread"); } } /** * This method loops forever waiting for data on the socket. When data * arrives, it clones a new instance of TCPServerSocket so the new * thread can deal with the data, while the current instance looks for new * data. The new thread deals with the data by calling handleIncomingRequest(). * * @see #handleIncomingRequest(java.net.Socket) */ public void run() { if (serverSocket != null) { boolean condition = true; while (condition) { try { byte buf [] = new byte[1000]; DatagramPacket dataUDP = new DatagramPacket(buf, buf.length); // Wait until data are received serverSocket.receive(dataUDP); MulticastUDPSocket newSocket = (MulticastUDPSocket) clone(); newSocket.serverSocket = null; newSocket.data = dataUDP; newSocket.ttl = ttl; // copy this, since it is no longer class static newSocket.parentSocket = this; // what was this for?? newSocket.runner = new Thread(newSocket); newSocket.runner.start(); } catch (IOException ioe) { if (serverSocket == null){ System.out.println("IOException in the main serverSocket : " + " serverSocket is null"); condition = false; } else { System.out.println("MulticastUDPSocket run IOexception: " +ioe); } } catch (CloneNotSupportedException cnse) { System.out.println("MulticastUDPSocket run CloningException: " +cnse); } } } else { handleIncomingRequest(data); } } /** * This method handles data received on a given TCPServerSocket. * Could be abstract since the method does nothing. A subclass is * expected to override this method to handle the incoming data as * necessary. * * @param data Socket the data is arriving on */ public void handleIncomingRequest(DatagramPacket data) { if (DEBUG) { System.out.println("in MulticastUDPSocket handleIncomingRequest(data)"); } /*// temp String info=""; info = info + " getAddress " + data.getAddress() + " length "+data.getLength(); info = info + " toString "+ data.toString(); //System.out.println("a recu info " + info); String resp = new String(data.getData()); resp = resp.trim(); System.out.println("reponse = " + resp+"/"); System.out.println("\nlength=" + resp.length()); if (resp.equalsIgnoreCase("end")){ System.out.println("veut arreter... fait arreter le pere"); parentSocket.stopServer(); } // end temp */ } public void sendPacket(String msg){ //if(msg.equals("") || msg==null) // msg = "empty message"; //System.out.println("msg = "+msg); DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.getBytes().length, group, portNumber); //System.out.println("ok dp " +dp.toString() + "port " +this.portNumber+ " group " + this.groupAddress); try { if (serverSocket!= null){ //System.out.println("current TTL : " + serverSocket.getTimeToLive ()); serverSocket.send(dp); } else System.out.println("serverSocket null " + serverSocket.toString()); } catch (IOException ioe){ System.out.println("in MulticastUDPSocket send" + ioe); } } /** * Returns the group address * * @return Address of the multicast group */ public String getMulticastGroup() { return groupAddress; } /** * Returns the port number of the multicast group * * @return Port number of the multicast group */ public int getMulticastPort() { return portNumber; } /** * */ /* public void setTTL (byte valueTTL) { this.ttl = valueTTL; } public static byte getTTL(){ return ttl; } */ /** * This method allows to set the TTL * * @param valueTTL The TTL */ public void setTTL (int ttl) { this.ttl = ttl; } /** * This method returns the Time To Live of the multicast socket * * @return int The TTL */ public int getTTL(){ return ttl; } // java context.arch.comm.protocol.MulticastUDPSocket /*public static void main (String arg[]){ System.out.println("ok"); MulticastUDPSocket mu = new MulticastUDPSocket(); //System.out.println("ok instanciation arg" + arg[0]); // To test the length of packets = 576 theorically StringBuffer s = new StringBuffer(""); String temp = "-abcd"; // 5 char int lg=0; for (int i=0; lg <2000 ; i++){ s.append(temp); s.append(i); lg = s.length(); } try { Thread.sleep(3000l); } catch (InterruptedException ie) { System.out.println("" + ie); } System.out.println("before starting mu"); System.out.println("s=" + s); System.out.println("length = "+s.length()+"\n\n"); try { Thread.sleep(3000l); } catch (InterruptedException ie) { System.out.println("" + ie); } mu.start(); /*for (int k=0 ; k<arg.length ; k++ ) { mu.sendPacket(arg[k]); System.out.println("main : k = "+k); try { Thread.sleep(3000l); } catch (InterruptedException ie) { System.out.println("" + ie); } } mu.sendPacket(s.toString()); //mu.stopServer(); } */ }