package org.webpieces.nio.test.suns;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import org.webpieces.util.logging.Logger;
import junit.framework.TestCase;
/**
* Bug internal review id: 494251
*
* setReuseAddress(true) appears not to work when the close is done
* while the selector thread is inside the selector making close not
* thread safe with the selector.
*/
public class TestCloseWhenInSelector extends TestCase {
private static final Logger log = Logger
.getLogger(TestCloseWhenInSelector.class);
private static final int CLIENT_PORT = 8023;
// private static final int CLIENT_PORT2 = 8002;
private static final int SERVER_PORT = 8020;
private SelectorProvider provider;
private AbstractSelector selector;
private ServerSocketChannel serverSocket;
// private SocketChannel serverChannel;
private SocketChannel client;
// private SocketChannel client2;
private ByteBuffer buf = ByteBuffer.allocate(10);
/**
* @param arg0
*/
public TestCloseWhenInSelector(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
provider = SelectorProvider.provider();
selector = provider.openSelector();
serverSocket = provider.openServerSocketChannel();
serverSocket.socket().setReuseAddress(true);
client = provider.openSocketChannel();
client.socket().setReuseAddress(true);
}
protected void tearDown() throws Exception {
}
/**
* This is testing a bug in the jdk where setReuseAddress to true is not
* working and I cannot rebind to the same address again.
*
* @throws Throwable
*/
public void testCloseWhenInSelector2() throws Throwable {
//the try catch is big because it can happen on the first connect or the last one
//depending on if you have run this test already!!!!
try {
InetAddress loopBack = InetAddress.getByName("127.0.0.1");
InetSocketAddress clientAddr = new InetSocketAddress(loopBack, CLIENT_PORT);
InetSocketAddress serverAddr = new InetSocketAddress(loopBack, SERVER_PORT);
//serverSocket.configureBlocking(false);
serverSocket.socket().bind(serverAddr);
client.socket().bind(clientAddr);
client.connect(serverAddr);
client.configureBlocking(false);
log.info("connecting client socket");
Thread.sleep(1000);
serverSocket.configureBlocking(true);
log.info("about to accept");
SocketChannel serverChannel = serverSocket.accept();
log.info("accepted");
serverChannel.configureBlocking(false);
log.info("client socket connected");
serverChannel.register(selector, SelectionKey.OP_READ);
PollingThread2 server = new PollingThread2();
server.start();
client.finishConnect();
log.info("write data to server");
ByteBuffer b = ByteBuffer.allocate(10);
b.putChar('d');
b.putChar('e');
b.flip();
log.info("write bytes");
int i = client.write(b);
log.info("wrote bytes="+i);
//wait for other thread to get into the selector...
Thread.sleep(1000);
log.info("1. closing client channel");
client.close();
log.info("1. closed client channel");
server.waitForCompletion();
client = provider.openSocketChannel();
client.socket().setReuseAddress(true);
client.socket().bind(clientAddr);
client.connect(serverAddr);
client.configureBlocking(false);
fail("setReuseAddress typically works but does not in this specific instance");
} catch(BindException e) {
}
}
private class PollingThread2 extends Thread {
private Throwable t = null;
private boolean socketClosed = false;
public void run() {
try {
log.info("STARTING RUN LOOP");
while(true) {
runLoop();
}
} catch (Exception e) {
t = e;
log.error("Test failure", e);
}
}
/**
*
*/
public synchronized void waitForCompletion() throws Throwable {
if(!socketClosed)
this.wait();
if(t != null)
throw t;
}
protected void runLoop() throws Exception {
log.info("going into selector");
int numKeys = selector.select();
log.info("coming out with new keys="+numKeys);
Set<SelectionKey> keySet = selector.selectedKeys();
log.info("keySet size="+keySet.size());
Iterator<SelectionKey> iter = keySet.iterator();
SelectionKey theKey = iter.next();
log.info("in loop iter.next="+theKey+" isVal="+theKey.isValid()+" acc="+theKey.isAcceptable()+" read="+theKey.isReadable());
if(theKey.isReadable()) {
SocketChannel channel = (SocketChannel)theKey.channel();
log.info("reading bytes");
int b = 5;
while(b > 0) {
b = channel.read(buf);
if(b < 0) {
channel.close();
synchronized(this) {
socketClosed = true;
this.notifyAll();
}
}
log.info("bytes read="+b);
}
}
if(iter.hasNext())
throw new RuntimeException("Fail test, iterator should only have one key");
}
}
}