package reactor.net.udp;
import io.netty.util.NetUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.Environment;
import reactor.function.Consumer;
import reactor.io.encoding.StandardCodecs;
import reactor.net.config.ServerSocketOptions;
import reactor.net.netty.udp.NettyDatagramServer;
import reactor.net.tcp.support.SocketUtils;
import reactor.net.udp.spec.DatagramServerSpec;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.Enumeration;
import java.util.Random;
import java.util.concurrent.*;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Jon Brisbin
*/
public class UdpServerTests {
final Logger log = LoggerFactory.getLogger(getClass());
Environment env;
ExecutorService threadPool;
@Before
public void setup() {
env = new Environment();
threadPool = Executors.newCachedThreadPool();
}
@After
public void cleanup() throws InterruptedException {
threadPool.shutdown();
threadPool.awaitTermination(5, TimeUnit.SECONDS);
}
@Test
@Ignore
public void supportsReceivingDatagrams() throws InterruptedException {
final int port = SocketUtils.findAvailableTcpPort();
final CountDownLatch latch = new CountDownLatch(4);
final DatagramServer<byte[], byte[]> server = new DatagramServerSpec<byte[], byte[]>(NettyDatagramServer.class)
.env(env)
.listen(port)
.codec(StandardCodecs.BYTE_ARRAY_CODEC)
.consumeInput(new Consumer<byte[]>() {
@Override
public void accept(byte[] bytes) {
if (bytes.length == 1024) {
latch.countDown();
}
}
})
.get();
server.start(new Runnable() {
@Override
public void run() {
try {
DatagramChannel udp = DatagramChannel.open();
udp.configureBlocking(true);
udp.connect(new InetSocketAddress(port));
byte[] data = new byte[1024];
new Random().nextBytes(data);
for (int i = 0; i < 4; i++) {
udp.write(ByteBuffer.wrap(data));
}
udp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
assertThat("latch was counted down", latch.await(5, TimeUnit.SECONDS));
}
@Test
@Ignore
public void supportsUdpMulticast() throws InterruptedException,
UnknownHostException,
SocketException,
TimeoutException,
ExecutionException {
final int port = SocketUtils.findAvailableTcpPort();
final CountDownLatch latch = new CountDownLatch(Environment.PROCESSORS ^ 2);
final InetAddress multicastGroup = InetAddress.getByName("230.0.0.1");
final NetworkInterface multicastIface = findMulticastInterface();
final DatagramServer[] servers = new DatagramServer[Environment.PROCESSORS];
for (int i = 0; i < Environment.PROCESSORS; i++) {
servers[i] = new DatagramServerSpec<byte[], byte[]>(NettyDatagramServer.class)
.env(env)
.dispatcher(Environment.THREAD_POOL)
.listen(port)
.multicastInterface(multicastIface)
.options(new ServerSocketOptions()
.reuseAddr(true))
.codec(StandardCodecs.BYTE_ARRAY_CODEC)
.consumeInput(new Consumer<byte[]>() {
int count = 0;
@SuppressWarnings("unchecked")
@Override
public void accept(byte[] bytes) {
//log.info("{} got {} bytes", ++count, bytes.length);
if (bytes.length == 1024) {
latch.countDown();
}
}
})
.get();
servers[i].start().await();
servers[i].join(multicastGroup).await();
}
for (int i = 0; i < Environment.PROCESSORS; i++) {
threadPool.submit(new Runnable() {
@Override
public void run() {
try {
MulticastSocket multicast = new MulticastSocket(port);
multicast.joinGroup(multicastGroup);
byte[] data = new byte[1024];
new Random().nextBytes(data);
multicast.send(new DatagramPacket(data, data.length, multicastGroup, port));
multicast.close();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}).get(5, TimeUnit.SECONDS);
}
assertThat("latch was counted down", latch.await(5, TimeUnit.SECONDS));
for (DatagramServer s : servers) {
s.shutdown().await();
}
}
private NetworkInterface findMulticastInterface() throws SocketException {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
if (!iface.isLoopback() && iface.supportsMulticast()) {
return iface;
}
}
return NetUtil.LOOPBACK_IF;
}
}