package water; import java.net.*; import water.util.Log; /** * The Thread that looks for Multicast UDP Cloud requests. * * This thread just spins on reading multicast UDP packets from the kernel and * either dispatching on them directly itself (if the request is known short) * or queuing them up for worker threads. Multicast *Channels* are available * Java 7, but we are writing to Java 6 JDKs. SO back to the old-school * MulticastSocket. * @author <a href="mailto:cliffc@h2o.ai"></a> * @version 1.0 */ class MultiReceiverThread extends Thread { MultiReceiverThread() { super("Multi-UDP-R"); } // The Run Method. // --- // Started by main() on a single thread, this code manages reading UDP packets @SuppressWarnings("resource") @Override public void run() { // No multicast? Then do not bother with listening for them if (H2O.isFlatfileEnabled()) return; Thread.currentThread().setPriority(Thread.MAX_PRIORITY); MulticastSocket sock = null, errsock = null; InetAddress group = null, errgroup = null; boolean saw_error = false; // Loop forever accepting Cloud Management requests while( true ) { try { // --- // Cleanup from any prior socket failures. Rare unless we're really sick. if( errsock != null && errgroup != null ) { // socket error AND group present final InetAddress tmp = errgroup; errgroup = null; errsock.leaveGroup(tmp); // Could throw, but errgroup cleared for next pass } if( errsock != null ) { // One time attempt a socket close final MulticastSocket tmp2 = errsock; errsock = null; tmp2.close(); // Could throw, but errsock cleared for next pass } if( saw_error ) Thread.sleep(1000); // prevent deny-of-service endless socket-creates saw_error = false; // --- // Actually do the common-case setup of Inet multicast group if( group == null ) group = H2O.CLOUD_MULTICAST_GROUP; // More common-case setup of a MultiCast socket if( sock == null ) { sock = new MulticastSocket(H2O.CLOUD_MULTICAST_PORT); if( H2O.CLOUD_MULTICAST_IF != null ) { try { sock.setNetworkInterface(H2O.CLOUD_MULTICAST_IF); } catch( SocketException e ) { Log.err("Exception calling setNetworkInterface, Multicast Interface, Group, Port - "+ H2O.CLOUD_MULTICAST_IF+" "+H2O.CLOUD_MULTICAST_GROUP+":"+H2O.CLOUD_MULTICAST_PORT, e); throw e; } } sock.joinGroup(group); } // Receive a packet & handle it byte[] buf = new byte[AutoBuffer.MTU]; DatagramPacket pack = new DatagramPacket(buf,buf.length); sock.receive(pack); UDPReceiverThread.basic_packet_handling(new AutoBuffer(pack)); } catch( SocketException e ) { // This rethrow will not be caught and thus kills the multi-cast thread. Log.err("Turning off multicast, which will disable further cloud building"); throw new RuntimeException(e); } catch( Exception e ) { Log.err("Exception on Multicast Interface, Group, Port - "+ H2O.CLOUD_MULTICAST_IF+" "+H2O.CLOUD_MULTICAST_GROUP+":"+H2O.CLOUD_MULTICAST_PORT, e); // On any error from anybody, close all sockets & re-open saw_error = true; errsock = sock ; sock = null; // Signal error recovery on the next loop errgroup = group; group = null; } } } }