/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Ignore; import org.junit.Test; import org.xnio.Buffers; import org.xnio.LocalSocketAddress; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.SocketAddressBuffer; /** * Test for the UDP channel. * * @author <a href="mailto:frainone@redhat.com">Flavia Rainone</a> * */ public class UdpChannelTestCase { private static final InetSocketAddress address1 = new InetSocketAddress("localhost", 1050); private static final InetSocketAddress address2 = new InetSocketAddress("localhost", 2050); private static final Xnio xnio = Xnio.getInstance(); @Test public void addressRetrieval() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); try { assertEquals(address1, server1.getLocalAddress()); assertEquals(address1, server1.getLocalAddress(InetSocketAddress.class)); assertNull(server1.getLocalAddress(LocalSocketAddress.class)); assertEquals(address2, server2.getLocalAddress()); assertEquals(address2, server2.getLocalAddress(InetSocketAddress.class)); assertNull(server2.getLocalAddress(LocalSocketAddress.class)); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); } } @Test public void testSimpleConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); final ByteBuffer receiveBuffer = ByteBuffer.allocate(10); SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(10, server1.receiveFrom(addressBuffer, receiveBuffer)); receiveBuffer.flip(); assertEquals("1234567890", Buffers.getModifiedUtf8(receiveBuffer)); assertEquals(address2, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffer.clear(); buffer.put("0987654321".getBytes()).flip(); assertTrue(server1.sendTo(address2, buffer)); receiveBuffer.clear(); addressBuffer = new SocketAddressBuffer(); assertEquals(10, server2.receiveFrom(null, receiveBuffer)); receiveBuffer.flip(); assertEquals("0987654321", Buffers.getModifiedUtf8(receiveBuffer)); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test @Ignore("Does not follow thread model") public void testChannelWithOneThreadOnly() throws IllegalArgumentException, IOException { final XnioWorker xnioWorker1 = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, 1)); final XnioWorker xnioWorker2 = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, 1)); final MulticastMessageChannel server1 = xnioWorker1.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker2.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put("msg to server 2".getBytes()).flip(); assertTrue(server1.sendTo(address2, buffer)); final ByteBuffer receiveBuffer = ByteBuffer.allocate(15); SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(15, server2.receiveFrom(addressBuffer, receiveBuffer)); receiveBuffer.flip(); assertEquals("msg to server 2", Buffers.getModifiedUtf8(receiveBuffer)); assertEquals(address1, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffer.clear(); buffer.put("msg to server 1".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); receiveBuffer.clear(); assertEquals(15, server1.receiveFrom(null, receiveBuffer)); receiveBuffer.flip(); assertEquals("msg to server 1", Buffers.getModifiedUtf8(receiveBuffer)); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); TestChannelListener<MulticastMessageChannel> server1Listener = new TestChannelListener<MulticastMessageChannel>(); server1.getWriteSetter().set(server1Listener); server1.resumeWrites(); server1.wakeupWrites(); assertTrue(server1Listener.isInvoked()); assertFalse(server1.isReadResumed()); assertTrue(server1.isWriteResumed()); server1.suspendReads(); server1.suspendWrites(); assertFalse(server1.isReadResumed()); assertFalse(server1.isWriteResumed()); TestChannelListener<MulticastMessageChannel> server2Listener = new TestChannelListener<MulticastMessageChannel>(); server2.getReadSetter().set(server2Listener); server2.resumeReads(); server2.wakeupReads(); assertTrue(server2Listener.isInvoked()); assertTrue(server2.isReadResumed()); assertFalse(server2.isWriteResumed()); server2.suspendReads(); server2.suspendWrites(); assertFalse(server2.isReadResumed()); assertFalse(server2.isWriteResumed()); } finally { server1.close(); server2.close(); xnioWorker1.shutdown(); xnioWorker2.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @SuppressWarnings("deprecation") @Test public void communicateUsingClosedChannel() throws IOException { final XnioWorker xnioWorker1 = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0)); final XnioWorker xnioWorker2 = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 0)); final MulticastMessageChannel server1 = xnioWorker1.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker2.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); server1.close(); assertFalse(server1.isOpen()); assertTrue(server2.isOpen()); try { assertTrue(server1.flush()); assertTrue(server2.flush()); final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put("attempt to send".getBytes()).flip(); ClosedChannelException expected = null; try { server1.sendTo(address2, buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { server1.sendTo(address2, new ByteBuffer[]{buffer}); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { server1.sendTo(address2, new ByteBuffer[]{buffer, buffer, buffer}, 0, 2); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); final SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); final ByteBuffer receiveBuffer = ByteBuffer.allocate(3); expected = null; assertEquals(-1, server1.receiveFrom(addressBuffer, receiveBuffer)); assertEquals(-1, server1.receiveFrom(addressBuffer, new ByteBuffer[]{receiveBuffer})); assertEquals(-1, server1.receiveFrom(addressBuffer, new ByteBuffer[]{receiveBuffer, receiveBuffer, receiveBuffer})); assertFalse(server2.sendTo(address1, buffer)); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffer)); assertTrue(server1.flush()); assertTrue(server1.flush()); assertTrue(server2.flush()); } finally { server2.close(); xnioWorker1.shutdown(); xnioWorker2.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test public void sendEmptyBuffer() throws IOException { @SuppressWarnings("deprecation") final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0)); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); assertTrue(server.isOpen()); try { assertFalse(server.sendTo(address2, Buffers.EMPTY_BYTE_BUFFER)); } finally { server.close(); xnioWorker.shutdown(); } } @Test public void sendAndReceiveMultipleBuffers() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer[] buffers = new ByteBuffer[] {Buffers.EMPTY_BYTE_BUFFER, ByteBuffer.allocate(10), ByteBuffer.allocate(5), ByteBuffer.allocate(1), ByteBuffer.allocate(1), ByteBuffer.allocate(1), ByteBuffer.allocate(2)}; buffers[1].put("nio udp".getBytes()).flip(); buffers[2].put("test".getBytes()).flip(); buffers[3].put((byte) 'c').flip(); buffers[4].put((byte) 'a').flip(); buffers[5].put((byte) 's').flip(); buffers[6].put("e!".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffers, 0, 2)); final ByteBuffer[] receiveBuffers = new ByteBuffer[]{ByteBuffer.allocate(5), ByteBuffer.allocate(6), ByteBuffer.allocate(8)}; SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(5, server1.receiveFrom(addressBuffer, receiveBuffers, 0, 1)); receiveBuffers[0].flip(); assertEquals("nio u", Buffers.getModifiedUtf8(receiveBuffers[0])); assertEquals(address2, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); receiveBuffers[0].clear(); assertEquals(0, server1.receiveFrom(null, receiveBuffers, 0, 1)); assertFalse(server1.sendTo(address2, buffers, 0, 0)); assertEquals(0, server2.receiveFrom(null, receiveBuffers, 2, 0)); assertTrue(server2.sendTo(address1, buffers, 2, 1)); assertEquals(4, server1.receiveFrom(null, receiveBuffers)); receiveBuffers[0].flip(); assertEquals("test", Buffers.getModifiedUtf8(receiveBuffers[0])); receiveBuffers[0].clear(); assertFalse(server1.sendTo(address2, buffers, 0, 2)); addressBuffer = new SocketAddressBuffer(); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffers, 0, 3)); assertEquals(address1, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); addressBuffer = new SocketAddressBuffer(); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffers, 0, 3)); assertNull(addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffers[1].flip(); buffers[2].flip(); assertTrue(server1.sendTo(address2, buffers)); assertEquals(16, server2.receiveFrom(addressBuffer, receiveBuffers)); receiveBuffers[0].flip(); assertEquals("nio u", Buffers.getModifiedUtf8(receiveBuffers[0])); receiveBuffers[1].flip(); assertEquals("dptest", Buffers.getModifiedUtf8(receiveBuffers[1])); receiveBuffers[2].flip(); assertEquals("case!", Buffers.getModifiedUtf8(receiveBuffers[2])); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test public void sendTooBigBuffer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); assertTrue(server.isOpen()); try { final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(65536), ByteBuffer.allocate(65536)}; buffers[0].limit(buffers[0].capacity()); IllegalArgumentException expected = null; try { server.sendTo(address1, buffers); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } finally { server.close(); xnioWorker.shutdown(); assertFalse(server.isOpen()); } } @Test public void shutdownReadsAndWrite() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); try { UnsupportedOperationException expected = null; try { server.shutdownReads(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { server.shutdownWrites(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } finally { server.close(); xnioWorker.shutdown(); } } @Test public void awaitReadableWritable() throws IOException, InterruptedException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); try { server1.awaitWritable(); final Thread readWaitThread1 = new Thread(new ReadableWaiter(server1)); final Thread readWaitThread2 = new Thread(new ReadableWaiter(server1, 7, TimeUnit.MICROSECONDS)); final Thread readWaitThread3 = new Thread(new ReadableWaiter(server1, 7, TimeUnit.DAYS)); readWaitThread1.start(); readWaitThread2.start(); readWaitThread3.start(); readWaitThread1.join(30); readWaitThread2.join(); readWaitThread3.join(30); assertTrue(readWaitThread1.isAlive()); assertTrue(readWaitThread3.isAlive()); server1.resumeReads(); readWaitThread1.join(20); readWaitThread3.join(20); assertTrue(readWaitThread1.isAlive()); assertTrue(readWaitThread3.isAlive()); final ByteBuffer buffer = ByteBuffer.allocate(3); buffer.put("msg".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); readWaitThread1.join(); readWaitThread3.join(); server1.awaitWritable(); server1.awaitWritable(10, TimeUnit.MICROSECONDS); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); } } // @Test // public void join() throws IOException { // final InetAddress address = InetAddress.getByName("225.0.0.100"); // final NetworkInterface ni = NetworkInterface.getByName("wlan0"); // assertNotNull(ni); // // final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); // final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.create(Options.MULTICAST, true)); // final InetSocketAddress address3 = new InetSocketAddress("localhost", 1051); // final InetSocketAddress address4 = new InetSocketAddress("localhost", 1052); // final InetSocketAddress address5 = new InetSocketAddress("localhost", 1053); // final InetSocketAddress address6 = new InetSocketAddress("localhost", 1054); // final InetSocketAddress address7 = new InetSocketAddress("localhost", 1055); // final MulticastMessageChannel server3 = xnioWorker.createUdpServer(address3, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server4 = xnioWorker.createUdpServer(address4, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server5 = xnioWorker.createUdpServer(address5, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server6 = xnioWorker.createUdpServer(address6, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server7 = xnioWorker.createUdpServer(address7, OptionMap.create(Options.MULTICAST, true)); // server1.setOption(Options.MULTICAST, true); // try { // server1.join(address, ni); // server2.join(address, ni); // server3.join(address, ni); // server4.join(address, ni); // // final ByteBuffer buffer = ByteBuffer.allocate(3); // buffer.put("abc".getBytes()).flip(); // // assertTrue(server5.sendTo(new InetSocketAddress(address, 950), buffer)); // // final ByteBuffer receiveBuffer = ByteBuffer.allocate(5); // SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); // assertEquals(3, server3.receiveFrom(addressBuffer, receiveBuffer)); // } finally { // server1.close(); // server2.close(); // server3.close(); // server4.close(); // server5.close(); // server6.close(); // server7.close(); // xnioWorker.shutdown(); // } // } @Test public void optionSetup() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final Option<?>[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.BROADCAST, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.IP_TRAFFIC_CLASS, Options.MULTICAST_TTL); try { for (Option<?> option: unsupportedOptions) { assertFalse("Server supports " + option, server.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + server.getOption(option) + " instead", server.getOption(option)); } assertTrue(server.supportsOption(Options.BROADCAST)); assertFalse(server.getOption(Options.BROADCAST)); assertTrue(server.supportsOption(Options.RECEIVE_BUFFER)); assertTrue(server.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(server.supportsOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.SEND_BUFFER) > 0); assertTrue(server.supportsOption(Options.IP_TRAFFIC_CLASS)); assertNotNull(server.getOption(Options.IP_TRAFFIC_CLASS)); assertTrue(server.supportsOption(Options.MULTICAST_TTL)); assertNotNull(server.getOption(Options.MULTICAST_TTL)); assertFalse(server.setOption(Options.BROADCAST, true)); assertTrue(server.setOption(Options.RECEIVE_BUFFER, 30000) > 0); assertTrue(server.setOption(Options.SEND_BUFFER, 3000) > 0); assertNotNull(server.setOption(Options.IP_TRAFFIC_CLASS, 200)); assertNotNull(server.setOption(Options.MULTICAST_TTL, 150)); assertNull(server.setOption(Options.REUSE_ADDRESSES, true)); assertTrue(server.getOption(Options.BROADCAST)); assertEquals(30000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(3000, (int) server.getOption(Options.SEND_BUFFER)); assertNotNull((int) server.getOption(Options.IP_TRAFFIC_CLASS)); // it is okay that 200 is not returned // 200 will only be set if the channels' family equals StandardProtocolFamily.INET assertEquals(150, (int) server.getOption(Options.MULTICAST_TTL)); assertNull(server.getOption(Options.REUSE_ADDRESSES)); } finally { server.close(); xnioWorker.shutdown(); } // TODO XNIO-171 we check setOption(*, null) } private class ReadableWaiter implements Runnable { private final MulticastMessageChannel channel; private final long timeout; private final TimeUnit timeoutUnit; public ReadableWaiter(MulticastMessageChannel c) { this(c, -1, null); } public ReadableWaiter(MulticastMessageChannel c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeout == -1) { channel.awaitReadable(); } else { channel.awaitReadable(timeout, timeoutUnit); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } }