public void testAcceptor() throws Exception { threadFactory.clear(); log.info("Test: testAcceptor"); final CountDownLatch ioLatch = new CountDownLatch(4); final CountDownLatch closeLatch = new CountDownLatch(2); final AtomicBoolean clientOpened = new AtomicBoolean(); final AtomicBoolean clientReadOnceOK = new AtomicBoolean(); final AtomicBoolean clientReadDoneOK = new AtomicBoolean(); final AtomicBoolean clientReadTooMuch = new AtomicBoolean(); final AtomicBoolean clientWriteOK = new AtomicBoolean(); final AtomicBoolean serverOpened = new AtomicBoolean(); final AtomicBoolean serverReadOnceOK = new AtomicBoolean(); final AtomicBoolean serverReadDoneOK = new AtomicBoolean(); final AtomicBoolean serverReadTooMuch = new AtomicBoolean(); final AtomicBoolean serverWriteOK = new AtomicBoolean(); final byte[] bytes = "Ummagumma!".getBytes("UTF-8"); final Xnio xnio = Xnio.getInstance("nio"); final ReadChannelThread readChannelThread = xnio.createReadChannelThread(threadFactory); final ReadChannelThread clientReadChannelThread = xnio.createReadChannelThread(threadFactory); final WriteChannelThread writeChannelThread = xnio.createWriteChannelThread(threadFactory); final WriteChannelThread clientWriteChannelThread = xnio.createWriteChannelThread(threadFactory); final ConnectionChannelThread connectionChannelThread = xnio.createConnectionChannelThread(threadFactory); try { final FutureResult<InetSocketAddress> futureAddressResult = new FutureResult<InetSocketAddress>(); final IoFuture<InetSocketAddress> futureAddress = futureAddressResult.getIoFuture(); final IoFuture<? extends ConnectedStreamChannel> futureConnection = xnio.acceptStream( new InetSocketAddress(Inet4Address.getByAddress(new byte[] {127, 0, 0, 1}), 0), connectionChannelThread, clientReadChannelThread, clientWriteChannelThread, new ChannelListener<ConnectedStreamChannel>() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final ConnectedStreamChannel channel) { channel .getCloseSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { closeLatch.countDown(); } }); channel .getReadSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { try { final int res = channel.read(inboundBuf); if (res == 0) { channel.resumeReads(); } else if (res == -1) { serverReadDoneOK.set(true); ioLatch.countDown(); channel.shutdownReads(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { serverReadOnceOK.set(true); } else if (ttl > bytes.length) { serverReadTooMuch.set(true); IoUtils.safeClose(channel); return; } channel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Server read failed"); IoUtils.safeClose(channel); } } }); channel .getWriteSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { try { channel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { serverWriteOK.set(true); Channels.shutdownWritesBlocking(channel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Server write failed"); IoUtils.safeClose(channel); } } }); channel.resumeReads(); channel.resumeWrites(); serverOpened.set(true); } }, new ChannelListener<BoundChannel>() { public void handleEvent(final BoundChannel channel) { futureAddressResult.setResult(channel.getLocalAddress(InetSocketAddress.class)); } }, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE)); final InetSocketAddress localAddress = futureAddress.get(); final IoFuture<? extends ConnectedStreamChannel> ioFuture = xnio.connectStream( localAddress, connectionChannelThread, readChannelThread, writeChannelThread, new ChannelListener<ConnectedStreamChannel>() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final ConnectedStreamChannel channel) { channel .getCloseSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { closeLatch.countDown(); } }); channel .getReadSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { try { final int res = channel.read(inboundBuf); if (res == 0) { channel.resumeReads(); } else if (res == -1) { channel.shutdownReads(); clientReadDoneOK.set(true); ioLatch.countDown(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { clientReadOnceOK.set(true); } else if (ttl > bytes.length) { clientReadTooMuch.set(true); IoUtils.safeClose(channel); return; } channel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Client read failed"); IoUtils.safeClose(channel); } } }); channel .getWriteSetter() .set( new ChannelListener<ConnectedStreamChannel>() { public void handleEvent(final ConnectedStreamChannel channel) { try { channel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { clientWriteOK.set(true); Channels.shutdownWritesBlocking(channel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Client write failed"); IoUtils.safeClose(channel); } } }); channel.resumeReads(); channel.resumeWrites(); clientOpened.set(true); } }, null, OptionMap.EMPTY); assertTrue("Read timed out", ioLatch.await(500L, TimeUnit.MILLISECONDS)); assertTrue("Close timed out", closeLatch.await(500L, TimeUnit.MILLISECONDS)); assertFalse("Client read too much", clientReadTooMuch.get()); assertTrue("Client read OK", clientReadOnceOK.get()); assertTrue("Client read done", clientReadDoneOK.get()); assertTrue("Client write OK", clientWriteOK.get()); assertFalse("Server read too much", serverReadTooMuch.get()); assertTrue("Server read OK", serverReadOnceOK.get()); assertTrue("Server read done", serverReadDoneOK.get()); assertTrue("Server write OK", serverWriteOK.get()); } finally { readChannelThread.shutdown(); writeChannelThread.shutdown(); clientReadChannelThread.shutdown(); clientWriteChannelThread.shutdown(); connectionChannelThread.shutdown(); } threadFactory.await(); }
private void doConnectionTest( final Runnable body, final ChannelListener<? super ConnectedStreamChannel> clientHandler, final ChannelListener<? super ConnectedStreamChannel> serverHandler) throws Exception { Xnio xnio = Xnio.getInstance("nio", NioTcpTestCase.class.getClassLoader()); final ConnectionChannelThread connectionChannelThread = xnio.createConnectionChannelThread(threadFactory); final ConnectionChannelThread serverChannelThread = xnio.createConnectionChannelThread(threadFactory); final ReadChannelThread readChannelThread = xnio.createReadChannelThread(threadFactory); final ReadChannelThread clientReadChannelThread = xnio.createReadChannelThread(threadFactory); final WriteChannelThread writeChannelThread = xnio.createWriteChannelThread(threadFactory); final WriteChannelThread clientWriteChannelThread = xnio.createWriteChannelThread(threadFactory); try { final AcceptingChannel<? extends ConnectedStreamChannel> server = xnio.createStreamServer( new InetSocketAddress( Inet4Address.getByAddress(new byte[] {127, 0, 0, 1}), SERVER_PORT), serverChannelThread, ChannelListeners.<ConnectedStreamChannel>openListenerAdapter( readChannelThread, writeChannelThread, new CatchingChannelListener<ConnectedStreamChannel>( serverHandler, threadFactory)), OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE)); server.resumeAccepts(); try { final IoFuture<? extends ConnectedStreamChannel> ioFuture = xnio.connectStream( new InetSocketAddress( Inet4Address.getByAddress(new byte[] {127, 0, 0, 1}), SERVER_PORT), connectionChannelThread, clientReadChannelThread, clientWriteChannelThread, new CatchingChannelListener<ConnectedStreamChannel>(clientHandler, threadFactory), null, OptionMap.EMPTY); final ConnectedStreamChannel channel = ioFuture.get(); try { body.run(); channel.close(); server.close(); } catch (Exception e) { log.errorf(e, "Error running body"); throw e; } catch (Error e) { log.errorf(e, "Error running body"); throw e; } finally { IoUtils.safeClose(channel); } } finally { IoUtils.safeClose(server); } } finally { connectionChannelThread.shutdown(); serverChannelThread.shutdown(); clientReadChannelThread.shutdown(); clientWriteChannelThread.shutdown(); readChannelThread.shutdown(); writeChannelThread.shutdown(); } connectionChannelThread.awaitTermination(); serverChannelThread.awaitTermination(); readChannelThread.awaitTermination(); writeChannelThread.awaitTermination(); clientReadChannelThread.awaitTermination(); clientWriteChannelThread.awaitTermination(); }