package test.udpbinding; import com.sun.grizzly.Controller; import com.sun.grizzly.ProtocolChainInstanceHandler; import com.sun.grizzly.DefaultProtocolChainInstanceHandler; import com.sun.grizzly.ProtocolChain; import com.sun.grizzly.DefaultProtocolChain; import com.sun.grizzly.UDPSelectorHandler; import com.sun.grizzly.ControllerStateListener; import com.sun.grizzly.ConnectorHandler; import com.sun.grizzly.ProtocolFilter; import com.sun.grizzly.Context; import com.sun.grizzly.SelectorHandler; import com.sun.grizzly.connectioncache.client.CacheableConnectorHandlerPool; import com.sun.grizzly.util.DefaultThreadPool; import com.sun.grizzly.filter.ReadFilter; import com.sun.grizzly.filter.LogFilter; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.SocketException; import java.net.DatagramSocket; import java.net.DatagramPacket; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.io.IOException; import java.nio.channels.DatagramChannel; /** * @author Bongjae Chang * @date 2009. 6. 9 */ public class DatagramSocketDuplicatedBindingTest { private static final int CORE_POOL_SIZE = 25; private static final int MAX_POOL_SIZE = 25; private static final int KEEP_ALIVE_TIMEOUT = 60 * 1000; // ms private static final int PORT = 9090; private static final int WAIT_FOR_BINDING = 2 * 1000; // ms private static final int SLEEP_TIME = 300; // ms private final InetAddress localInetAddress; private final InetSocketAddress localInetSocketAddress; private final CountDownLatch latchForSending = new CountDownLatch( 1 ); private DatagramSocketDuplicatedBindingTest() throws UnknownHostException { localInetAddress = InetAddress.getLocalHost(); localInetSocketAddress = new InetSocketAddress( localInetAddress, PORT ); } private void testSimpleSendAndReceive() throws IOException { final Controller server = new Controller(); setupAndStartController( server, true ); new Thread( new DatagramSocketDuplicatedBindingTest.DatagramSocketClient() ).start(); System.out.println( "Wait for " + WAIT_FOR_BINDING + "(ms)" ); try { Thread.sleep( WAIT_FOR_BINDING ); } catch( InterruptedException e ) { } final Controller client = new Controller(); setupAndStartController( client, false ); System.out.println( "###Binding duplicated socket again..###" ); // test #1 // reproduce the problem /* for( int i = 0; i < 100; i++ ) { DatagramChannel newDatagramChannel = DatagramChannel.open(); newDatagramChannel.socket().setReuseAddress( true ); if( localInetSocketAddress != null ) { newDatagramChannel.socket().bind( localInetSocketAddress ); } } */ // test #2 // blocking DatagramSocket binding test /* DatagramSocket duplicatedBindingSocket = new DatagramSocket( localInetSocketAddress ); */ // test #3 // receiver's switch test // /* ConnectorHandler connectorHandler = null; try { connectorHandler = client.acquireConnectorHandler( Controller.Protocol.UDP ); connectorHandler.connect( localInetSocketAddress, localInetSocketAddress ); } finally { if( connectorHandler != null ) { try { connectorHandler.close(); } catch( IOException e ) { e.printStackTrace(); } client.releaseConnectorHandler( connectorHandler ); } } // */ } private void setupAndStartController( final Controller controller, final boolean server ) { UDPSelectorHandler udpSelectorHandler; controller.setThreadPool( new DefaultThreadPool( server ? "server" : "client", CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIMEOUT, TimeUnit.MILLISECONDS ) ); if( server ) { udpSelectorHandler = new UDPSelectorHandler(); } else { CacheableConnectorHandlerPool connectorHandlerPool = new CacheableConnectorHandlerPool( controller, 100, 10, 1 ); controller.setConnectorHandlerPool( connectorHandlerPool ); udpSelectorHandler = new UDPSelectorHandler( true ); } udpSelectorHandler.setPort( PORT ); udpSelectorHandler.setInet( localInetAddress ); controller.addSelectorHandler( udpSelectorHandler ); ProtocolChainInstanceHandler pciHandler = new DefaultProtocolChainInstanceHandler() { @Override public ProtocolChain poll() { ProtocolChain protocolChain = protocolChains.poll(); if( protocolChain == null ) { protocolChain = new DefaultProtocolChain(); protocolChain.addFilter( new ReadFilter() ); protocolChain.addFilter( new ProtocolFilter() { public boolean execute( Context ctx ) throws IOException { System.out.print( "current thread: " + Thread.currentThread() + ", " ); return true; } public boolean postExecute( Context ctx ) throws IOException { return true; } } ); protocolChain.addFilter( new LogFilter() ); } return protocolChain; } }; controller.setProtocolChainInstanceHandler( pciHandler ); final CountDownLatch controllerGate = new CountDownLatch( 1 ); ControllerStateListener controllerStateListener = new ControllerStateListener() { public void onStarted() { } public void onReady() { controllerGate.countDown(); } public void onStopped() { controllerGate.countDown(); } public void onException( Throwable throwable ) { controllerGate.countDown(); } }; controller.addStateListener( controllerStateListener ); new Thread( controller ).start(); try { controllerGate.await(); } catch( InterruptedException e ) { e.printStackTrace(); } latchForSending.countDown(); } public static void main( String[] args ) throws IOException { DatagramSocketDuplicatedBindingTest test = new DatagramSocketDuplicatedBindingTest(); test.testSimpleSendAndReceive(); } private class DatagramSocketClient implements Runnable { private boolean running; private DatagramSocket client; private int sendCount; private DatagramSocketClient() throws SocketException { client = new DatagramSocket( PORT ); } public void run() { if( client == null ) return; running = true; try { latchForSending.await(); while( running ) { sendCount++; byte[] testPacket = new String( "hello world-" + sendCount ).getBytes(); DatagramPacket packet = new DatagramPacket( testPacket, testPacket.length, localInetSocketAddress ); client.send( packet ); try { Thread.sleep( SLEEP_TIME ); } catch( InterruptedException e ) { } } } catch( Throwable t ) { t.printStackTrace(); } finally { if( client != null ) { client.close(); client = null; } running = false; System.out.println( "Client socket is finished.." ); } } } }