From 115e56bd7bf9e160dbaa52194a3ce28ef1aa1a39 Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Tue, 12 Nov 2019 01:45:57 +0900 Subject: [PATCH 01/11] get basic udp server/client working --- .../transport/quic/BasicQuicTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java new file mode 100644 index 00000000000..921691a5d29 --- /dev/null +++ b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java @@ -0,0 +1,85 @@ +package io.netty.testsuite.transport.quic; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.MultithreadEventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioHandler; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.logging.LoggingHandler; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +public class BasicQuicTest { + @Test + public void testSimpleEcho() throws Throwable { + final MultithreadEventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory()); + final Bootstrap b = new Bootstrap(); + b.group(group).channel(NioDatagramChannel.class) + .option(ChannelOption.SO_BROADCAST, true) + .handler(new ChannelInitializer() { + @Override + public void initChannel(final NioDatagramChannel ch) throws Exception { + + final ChannelPipeline p = ch.pipeline(); + p.addLast(new LoggingHandler()); + p.addLast(new SimpleChannelInboundHandler() { + @Override + protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { + final InetAddress srcAddr = msg.sender().getAddress(); + final ByteBuf buf = msg.content(); + final int rcvPktLength = buf.readableBytes(); + final byte[] rcvPktBuf = new byte[rcvPktLength]; + buf.readBytes(rcvPktBuf); + System.out.println("Inside incomming packet handler"); + + } + }); + } + }); + + // Bind and start to accept incoming connections. + Channel channel = b.bind(new InetSocketAddress(20080)).sync().channel(); + channel.closeFuture().await(); + } + + @Test + public void testSimpleClient() throws Exception { + final Bootstrap bootstrap = new Bootstrap(); + final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); + bootstrap.group(workerGroup) + .channel(NioDatagramChannel.class) + .option(ChannelOption.SO_BROADCAST, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(NioDatagramChannel ch)throws Exception { + final ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new ChannelHandler() { + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("hai:)".getBytes()), new InetSocketAddress(20080))); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + System.out.println("msg: " + msg); + } + }); + } + }); + final ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(20080)).sync(); + System.out.println(channelFuture.channel().remoteAddress()); + channelFuture.channel().closeFuture().await(1000); + } +} From f21fd21e1a5d3c6a23c68495fa22df5c61240a93 Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Wed, 13 Nov 2019 00:41:43 +0900 Subject: [PATCH 02/11] clean up udp unit test to run without server setup --- .../transport/quic/BasicQuicTest.java | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java index 921691a5d29..79df9070a91 100644 --- a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java +++ b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java @@ -5,7 +5,6 @@ import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; @@ -18,12 +17,42 @@ import io.netty.handler.logging.LoggingHandler; import org.junit.Test; -import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import static org.junit.Assert.*; + public class BasicQuicTest { + + private static final String ECHO_MESSAGE = "hai:)"; + @Test public void testSimpleEcho() throws Throwable { + + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference result = new AtomicReference<>(); + + final Channel serverChannel = setupServer(retval -> { + result.set(retval); + latch.countDown(); + }); + + final Channel clientChannel = getClient(); + clientChannel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer( + ECHO_MESSAGE.getBytes()), new InetSocketAddress(20080))).sync(); + + latch.await(); + + assertEquals(ECHO_MESSAGE, result.get()); + + serverChannel.close().await(); + clientChannel.close().await(); + } + + private static Channel setupServer(Consumer validator) throws Exception { final MultithreadEventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory()); final Bootstrap b = new Bootstrap(); b.group(group).channel(NioDatagramChannel.class) @@ -37,25 +66,19 @@ public void initChannel(final NioDatagramChannel ch) throws Exception { p.addLast(new SimpleChannelInboundHandler() { @Override protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { - final InetAddress srcAddr = msg.sender().getAddress(); final ByteBuf buf = msg.content(); final int rcvPktLength = buf.readableBytes(); final byte[] rcvPktBuf = new byte[rcvPktLength]; buf.readBytes(rcvPktBuf); - System.out.println("Inside incomming packet handler"); - + validator.accept(new String(rcvPktBuf)); } }); } }); - - // Bind and start to accept incoming connections. - Channel channel = b.bind(new InetSocketAddress(20080)).sync().channel(); - channel.closeFuture().await(); + return b.bind(new InetSocketAddress(20080)).sync().await().channel(); } - @Test - public void testSimpleClient() throws Exception { + public static Channel getClient() throws Exception { final Bootstrap bootstrap = new Bootstrap(); final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); bootstrap.group(workerGroup) @@ -64,22 +87,9 @@ public void testSimpleClient() throws Exception { .handler(new ChannelInitializer() { @Override protected void initChannel(NioDatagramChannel ch)throws Exception { - final ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new ChannelHandler() { - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("hai:)".getBytes()), new InetSocketAddress(20080))); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - System.out.println("msg: " + msg); - } - }); } }); final ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(20080)).sync(); - System.out.println(channelFuture.channel().remoteAddress()); - channelFuture.channel().closeFuture().await(1000); + return channelFuture.channel(); } } From db5f66ad668c9f36c9d536f8a71f170fe3e6503e Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Wed, 13 Nov 2019 00:55:55 +0900 Subject: [PATCH 03/11] add chromium endpoint to test --- .../java/io/netty/testsuite/transport/quic/BasicQuicTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java index 79df9070a91..8b3114496f1 100644 --- a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java +++ b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java @@ -28,6 +28,7 @@ public class BasicQuicTest { private static final String ECHO_MESSAGE = "hai:)"; + private static final String CHROMIUM_ENDPOINT = "https://quic.rocks:4433/"; @Test public void testSimpleEcho() throws Throwable { From eddc01e2a21550060113928f10c20e7b6ece4e28 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 13 Nov 2019 23:43:46 +0900 Subject: [PATCH 04/11] get started with attempting to send quic initial packet --- .../transport/quic/BasicQuicTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java index 8b3114496f1..9a498addfc8 100644 --- a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java +++ b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java @@ -2,6 +2,7 @@ import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -15,8 +16,10 @@ import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.handler.logging.LoggingHandler; +import io.netty.resolver.InetNameResolver; import org.junit.Test; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; @@ -29,6 +32,7 @@ public class BasicQuicTest { private static final String ECHO_MESSAGE = "hai:)"; private static final String CHROMIUM_ENDPOINT = "https://quic.rocks:4433/"; + private static final InetSocketAddress remote = new InetSocketAddress("cloudflare-quic.com", 443);; @Test public void testSimpleEcho() throws Throwable { @@ -53,6 +57,34 @@ public void testSimpleEcho() throws Throwable { clientChannel.close().await(); } + @Test + public void longHeaderPacket() throws Exception { + byte[] headerForm = { + (byte) ((0x80 & 0xff) + (0x40 & 0xff)), + (byte) 0xff, 0, 0x00, 0x17, + 1, (byte) 0, 1, (byte) 0, + 0, 0, 1, 0 + }; + +// final ByteBuf byteBuf = Unpooled.copyInt(headerForm); + final ByteBuf byteBuf = Unpooled.copiedBuffer(headerForm); + System.out.println(ByteBufUtil.prettyHexDump(byteBuf)); + + final byte[] bytes = ByteBufUtil.decodeHexDump("07ff706cb107568ef7116f5f58a9ed9010"); + final ByteBuf byteBufFromInternet = Unpooled.copiedBuffer(bytes); + System.out.println(ByteBufUtil.prettyHexDump(Unpooled.copiedBuffer(bytes))); + + final Channel client = getRemoteClient(); + client.writeAndFlush(new DatagramPacket(byteBufFromInternet, remote)).sync(); + client.closeFuture().await(); + } + + @Test + public void initialPacket() { + final byte[] bytes = ByteBufUtil.decodeHexDump("07ff706cb107568ef7116f5f58a9ed9010"); + System.out.println(ByteBufUtil.prettyHexDump(Unpooled.copiedBuffer(bytes)));; + } + private static Channel setupServer(Consumer validator) throws Exception { final MultithreadEventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory()); final Bootstrap b = new Bootstrap(); @@ -88,9 +120,34 @@ public static Channel getClient() throws Exception { .handler(new ChannelInitializer() { @Override protected void initChannel(NioDatagramChannel ch)throws Exception { + final ChannelPipeline p = ch.pipeline(); + p.addLast(new LoggingHandler()); } }); final ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(20080)).sync(); return channelFuture.channel(); } + + public static Channel getRemoteClient() throws Exception { + final Bootstrap bootstrap = new Bootstrap(); + final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); + bootstrap.group(workerGroup) + .channel(NioDatagramChannel.class) + .option(ChannelOption.SO_BROADCAST, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(NioDatagramChannel ch)throws Exception { + final ChannelPipeline p = ch.pipeline(); + p.addLast(new LoggingHandler()); + p.addLast(new SimpleChannelInboundHandler() { + @Override + protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { + System.out.println(msg); + } + }); + } + }); + final ChannelFuture channelFuture = bootstrap.connect(remote).sync(); + return channelFuture.channel(); + } } From 064998d78cde54cbe52fdbcb57fc676b1e3ae3df Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Thu, 14 Nov 2019 01:29:37 +0900 Subject: [PATCH 05/11] successfully send initial packet --- .../transport/quic/BasicQuicTest.java | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java index 9a498addfc8..1192e660d00 100644 --- a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java +++ b/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java @@ -16,10 +16,8 @@ import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.handler.logging.LoggingHandler; -import io.netty.resolver.InetNameResolver; import org.junit.Test; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; @@ -32,7 +30,7 @@ public class BasicQuicTest { private static final String ECHO_MESSAGE = "hai:)"; private static final String CHROMIUM_ENDPOINT = "https://quic.rocks:4433/"; - private static final InetSocketAddress remote = new InetSocketAddress("cloudflare-quic.com", 443);; + @Test public void testSimpleEcho() throws Throwable { @@ -45,38 +43,45 @@ public void testSimpleEcho() throws Throwable { latch.countDown(); }); - final Channel clientChannel = getClient(); + final InetSocketAddress recipient = new InetSocketAddress(20080); + final Channel clientChannel = getClient(recipient, ignored -> {}); clientChannel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer( - ECHO_MESSAGE.getBytes()), new InetSocketAddress(20080))).sync(); + ECHO_MESSAGE.getBytes()), recipient)).sync(); latch.await(); assertEquals(ECHO_MESSAGE, result.get()); - serverChannel.close().await(); - clientChannel.close().await(); + serverChannel.closeFuture().await(); + clientChannel.closeFuture().await(); } @Test - public void longHeaderPacket() throws Exception { - byte[] headerForm = { + public void trySendInitialPacket() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference result = new AtomicReference<>(); + + final byte[] headerForm = { (byte) ((0x80 & 0xff) + (0x40 & 0xff)), - (byte) 0xff, 0, 0x00, 0x17, - 1, (byte) 0, 1, (byte) 0, + (byte) 0, 0, 0, 0x01, + (byte) 0, 0, 0, 0, 0, 0, 1, 0 }; -// final ByteBuf byteBuf = Unpooled.copyInt(headerForm); final ByteBuf byteBuf = Unpooled.copiedBuffer(headerForm); System.out.println(ByteBufUtil.prettyHexDump(byteBuf)); - final byte[] bytes = ByteBufUtil.decodeHexDump("07ff706cb107568ef7116f5f58a9ed9010"); - final ByteBuf byteBufFromInternet = Unpooled.copiedBuffer(bytes); - System.out.println(ByteBufUtil.prettyHexDump(Unpooled.copiedBuffer(bytes))); + final InetSocketAddress remote = new InetSocketAddress("quic.tech", 4433); + final Channel client = getClient(remote, newValue -> { + latch.countDown(); + result.set(newValue); + }); + client.writeAndFlush(new DatagramPacket(byteBuf, remote)).sync(); - final Channel client = getRemoteClient(); - client.writeAndFlush(new DatagramPacket(byteBufFromInternet, remote)).sync(); - client.closeFuture().await(); + latch.await(); + assertNotNull(result.get()); + + client.close().await(); } @Test @@ -105,30 +110,18 @@ protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) th buf.readBytes(rcvPktBuf); validator.accept(new String(rcvPktBuf)); } - }); - } - }); - return b.bind(new InetSocketAddress(20080)).sync().await().channel(); - } - public static Channel getClient() throws Exception { - final Bootstrap bootstrap = new Bootstrap(); - final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); - bootstrap.group(workerGroup) - .channel(NioDatagramChannel.class) - .option(ChannelOption.SO_BROADCAST, true) - .handler(new ChannelInitializer() { @Override - protected void initChannel(NioDatagramChannel ch)throws Exception { - final ChannelPipeline p = ch.pipeline(); - p.addLast(new LoggingHandler()); + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + System.out.println(cause); } }); - final ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(20080)).sync(); - return channelFuture.channel(); + } + }); + return b.bind(new InetSocketAddress(20080)).sync().await().channel(); } - public static Channel getRemoteClient() throws Exception { + public static Channel getClient(InetSocketAddress address, Consumer validator) throws Exception { final Bootstrap bootstrap = new Bootstrap(); final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); bootstrap.group(workerGroup) @@ -142,12 +135,16 @@ protected void initChannel(NioDatagramChannel ch)throws Exception { p.addLast(new SimpleChannelInboundHandler() { @Override protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { - System.out.println(msg); + final ByteBuf buf = msg.content(); + final int rcvPktLength = buf.readableBytes(); + final byte[] rcvPktBuf = new byte[rcvPktLength]; + buf.readBytes(rcvPktBuf); + validator.accept(new String(rcvPktBuf)); } }); } }); - final ChannelFuture channelFuture = bootstrap.connect(remote).sync(); + final ChannelFuture channelFuture = bootstrap.connect(address).sync(); return channelFuture.channel(); } } From 9b30cdd5bad16ebd0645c5605197a54b237ca2d4 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 16 Nov 2019 23:15:05 +0900 Subject: [PATCH 06/11] create a new quic module --- codec-quic/pom.xml | 58 +++++++++++++++++++ .../handler/codec/quic/QuicClientHandler.java | 17 ++++++ .../handler/codec}/quic/BasicQuicTest.java | 34 ++++++++--- pom.xml | 1 + 4 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 codec-quic/pom.xml create mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java rename {testsuite/src/main/java/io/netty/testsuite/transport => codec-quic/src/test/java/io/netty/handler/codec}/quic/BasicQuicTest.java (84%) diff --git a/codec-quic/pom.xml b/codec-quic/pom.xml new file mode 100644 index 00000000000..d29a1c72511 --- /dev/null +++ b/codec-quic/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + io.netty + netty-parent + 5.0.0.Final-SNAPSHOT + + + netty-codec-quic + jar + + Netty/Codec/Quic + + + io.netty.codec.quic + + + + + ${project.groupId} + netty-common + ${project.version} + + + ${project.groupId} + netty-buffer + ${project.version} + + + ${project.groupId} + netty-transport + ${project.version} + + + ${project.groupId} + netty-codec + ${project.version} + + + ${project.groupId} + netty-handler + ${project.version} + + + com.jcraft + jzlib + true + + + org.mockito + mockito-core + + + \ No newline at end of file diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java new file mode 100644 index 00000000000..d55a1efc6a1 --- /dev/null +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java @@ -0,0 +1,17 @@ +package io.netty.handler.codec.quic; + +import io.netty.channel.ChannelHandlerAdapter; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +public class QuicClientHandler extends ChannelHandlerAdapter { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicClientHandler.class); + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + super.channelRead(ctx, msg); + logger.info("msg: {}", msg); + } +} diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java similarity index 84% rename from testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java rename to codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java index 1192e660d00..c77a8f91c8f 100644 --- a/testsuite/src/main/java/io/netty/testsuite/transport/quic/BasicQuicTest.java +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java @@ -1,4 +1,4 @@ -package io.netty.testsuite.transport.quic; +package io.netty.handler.codec.quic; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; @@ -59,7 +59,7 @@ public void testSimpleEcho() throws Throwable { @Test public void trySendInitialPacket() throws Exception { final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference result = new AtomicReference<>(); + final AtomicReference result = new AtomicReference<>(); final byte[] headerForm = { (byte) ((0x80 & 0xff) + (0x40 & 0xff)), @@ -72,9 +72,14 @@ public void trySendInitialPacket() throws Exception { System.out.println(ByteBufUtil.prettyHexDump(byteBuf)); final InetSocketAddress remote = new InetSocketAddress("quic.tech", 4433); - final Channel client = getClient(remote, newValue -> { + final Channel client = getClient(remote, res -> { + +// final int rcvPktLength = buf.readableBytes(); +// final byte[] rcvPktBuf = new byte[rcvPktLength]; +// buf.readBytes(rcvPktBuf); + result.set(Unpooled.copiedBuffer(res)); + latch.countDown(); - result.set(newValue); }); client.writeAndFlush(new DatagramPacket(byteBuf, remote)).sync(); @@ -82,6 +87,19 @@ public void trySendInitialPacket() throws Exception { assertNotNull(result.get()); client.close().await(); + + final ByteBuf resByteBuf = result.get().duplicate(); + System.out.println(ByteBufUtil.hexDump(resByteBuf.duplicate())); + while (resByteBuf.readableBytes() > 0) { + printSingleByte(resByteBuf); + } + System.out.println(); + + } + + private void printSingleByte(ByteBuf resByteBuf) { + final byte b = resByteBuf.readByte(); + System.out.println(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0')); } @Test @@ -121,7 +139,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E return b.bind(new InetSocketAddress(20080)).sync().await().channel(); } - public static Channel getClient(InetSocketAddress address, Consumer validator) throws Exception { + public static Channel getClient(InetSocketAddress address, Consumer validator) throws Exception { final Bootstrap bootstrap = new Bootstrap(); final MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); bootstrap.group(workerGroup) @@ -132,14 +150,12 @@ public static Channel getClient(InetSocketAddress address, Consumer vali protected void initChannel(NioDatagramChannel ch)throws Exception { final ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler()); + p.addLast(new QuicClientHandler()); p.addLast(new SimpleChannelInboundHandler() { @Override protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { final ByteBuf buf = msg.content(); - final int rcvPktLength = buf.readableBytes(); - final byte[] rcvPktBuf = new byte[rcvPktLength]; - buf.readBytes(rcvPktBuf); - validator.accept(new String(rcvPktBuf)); + validator.accept(buf); } }); } diff --git a/pom.xml b/pom.xml index 1f763d5e6ee..c4e5a42ab65 100644 --- a/pom.xml +++ b/pom.xml @@ -372,6 +372,7 @@ transport-blockhound-tests microbench bom + codec-quic From 7cfe3dad01ff9b8cfb9353fab5a79b309abcf7db Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Sun, 17 Nov 2019 01:31:26 +0900 Subject: [PATCH 07/11] use a dedicated decoder for quic response parsing --- .../handler/codec/quic/QuicClientHandler.java | 17 ------------- .../netty/handler/codec/quic/QuicMessage.java | 15 ++++++++++++ .../codec/quic/QuicResponseDecoder.java | 24 +++++++++++++++++++ .../handler/codec/quic/BasicQuicTest.java | 13 ++++------ 4 files changed, 43 insertions(+), 26 deletions(-) delete mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java create mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java create mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java deleted file mode 100644 index d55a1efc6a1..00000000000 --- a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicClientHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.netty.handler.codec.quic; - -import io.netty.channel.ChannelHandlerAdapter; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -public class QuicClientHandler extends ChannelHandlerAdapter { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicClientHandler.class); - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - super.channelRead(ctx, msg); - logger.info("msg: {}", msg); - } -} diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java new file mode 100644 index 00000000000..d906eb46405 --- /dev/null +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java @@ -0,0 +1,15 @@ +package io.netty.handler.codec.quic; + +import io.netty.buffer.ByteBuf; + +public class QuicMessage { + ByteBuf byteBuf; + + public QuicMessage(ByteBuf byteBuf) { + this.byteBuf = byteBuf; + } + + public ByteBuf getByteBuf() { + return byteBuf; + } +} diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java new file mode 100644 index 00000000000..e14a7704f46 --- /dev/null +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java @@ -0,0 +1,24 @@ +package io.netty.handler.codec.quic; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.DatagramPacket; +import io.netty.handler.codec.ByteToMessageDecoder; +import io.netty.handler.codec.MessageToMessageDecoder; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +import java.util.List; + +public class QuicResponseDecoder extends MessageToMessageDecoder { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicResponseDecoder.class); + + @Override + protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List out) throws Exception { + final ByteBuf byteBuf = msg.content(); + logger.info("decoding byteBuf: {}", byteBuf); + out.add(new QuicMessage(ReferenceCountUtil.retain(byteBuf))); + } +} diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java index c77a8f91c8f..56a02bcb914 100644 --- a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java @@ -73,12 +73,7 @@ public void trySendInitialPacket() throws Exception { final InetSocketAddress remote = new InetSocketAddress("quic.tech", 4433); final Channel client = getClient(remote, res -> { - -// final int rcvPktLength = buf.readableBytes(); -// final byte[] rcvPktBuf = new byte[rcvPktLength]; -// buf.readBytes(rcvPktBuf); result.set(Unpooled.copiedBuffer(res)); - latch.countDown(); }); client.writeAndFlush(new DatagramPacket(byteBuf, remote)).sync(); @@ -150,11 +145,11 @@ public static Channel getClient(InetSocketAddress address, Consumer val protected void initChannel(NioDatagramChannel ch)throws Exception { final ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler()); - p.addLast(new QuicClientHandler()); - p.addLast(new SimpleChannelInboundHandler() { + p.addLast(new QuicResponseDecoder()); + p.addLast(new SimpleChannelInboundHandler() { @Override - protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { - final ByteBuf buf = msg.content(); + protected void messageReceived(ChannelHandlerContext ctx, QuicMessage msg) throws Exception { + final ByteBuf buf = msg.getByteBuf(); validator.accept(buf); } }); From 6a14f75ddf9b864edcdd3f6c28a956f6cd8d6981 Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Sun, 17 Nov 2019 11:06:28 +0900 Subject: [PATCH 08/11] add decoding for long type header packets --- .../codec/quic/QuicResponseDecoder.java | 66 ++++++++++++++++++- .../handler/codec/quic/BasicQuicTest.java | 12 ---- .../codec/quic/QuicResponseDecoderTest.java | 28 ++++++++ 3 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 codec-quic/src/test/java/io/netty/handler/codec/quic/QuicResponseDecoderTest.java diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java index e14a7704f46..9debe7de49f 100644 --- a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java @@ -3,7 +3,6 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.socket.DatagramPacket; -import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.logging.InternalLogger; @@ -15,10 +14,73 @@ public class QuicResponseDecoder extends MessageToMessageDecoder private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicResponseDecoder.class); + private enum State { + INITIAL, + HEADER, + DCID_LEN + } + + private State state = State.INITIAL; + @Override protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List out) throws Exception { final ByteBuf byteBuf = msg.content(); - logger.info("decoding byteBuf: {}", byteBuf); + + + + switch (state) { + case INITIAL: + if (!byteBuf.isReadable()) { + return; + } + final byte headerByte = byteBuf.readByte(); + final boolean headerForm = headerForm(headerByte); + + // only process long header packets for now... + if (!headerForm) { + logger.info("headerForm: {}", headerForm); + return; + } + + final boolean fixedBit = fixedBit(headerByte); + final short longPacketType = longPacketType(headerByte); + final int typeSpecificBits = typeSpecificBits(headerByte); + logger.info("headerForm: {}, fixedBit: {}, longPacketType: {}, typeSpecificBits: {}", + headerForm, fixedBit, longPacketType, typeSpecificBits); + state = State.HEADER; + case HEADER: + if (!byteBuf.isReadable(4)) { + return; + } + final ByteBuf versionByteBuf = byteBuf.readBytes(4); + final int version = versionByteBuf.readInt(); + logger.info("version: {}", version); + state = State.DCID_LEN; + case DCID_LEN: + if (!byteBuf.isReadable()) { + return; + } + final byte dcidLenByte = byteBuf.readByte(); + logger.info("dcidLenByte: {}", dcidLenByte); + + } + out.add(new QuicMessage(ReferenceCountUtil.retain(byteBuf))); } + + static int typeSpecificBits(byte b) { + return b & 0x0f; + } + + static short longPacketType(byte b) { + return (short) ((b & 0x30) >> 4); + } + + static boolean fixedBit(byte b) { + return (b & 0x40) >> 6 == 1; + } + + static boolean headerForm(byte b) { + return (b & 0x80) >> 7 == 1; + } } diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java index 56a02bcb914..0b34b9f6e10 100644 --- a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java @@ -83,18 +83,6 @@ public void trySendInitialPacket() throws Exception { client.close().await(); - final ByteBuf resByteBuf = result.get().duplicate(); - System.out.println(ByteBufUtil.hexDump(resByteBuf.duplicate())); - while (resByteBuf.readableBytes() > 0) { - printSingleByte(resByteBuf); - } - System.out.println(); - - } - - private void printSingleByte(ByteBuf resByteBuf) { - final byte b = resByteBuf.readByte(); - System.out.println(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0')); } @Test diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicResponseDecoderTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicResponseDecoderTest.java new file mode 100644 index 00000000000..6f167bbb85e --- /dev/null +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicResponseDecoderTest.java @@ -0,0 +1,28 @@ +package io.netty.handler.codec.quic; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class QuicResponseDecoderTest { + + @Test + public void testHeaderForm() { + assertTrue(QuicResponseDecoder.headerForm((byte) 0b10000000)); + assertFalse(QuicResponseDecoder.headerForm((byte) 0b00000000)); + } + + @Test + public void testFixedBit() { + assertTrue(QuicResponseDecoder.fixedBit((byte) 0b01000000)); + assertFalse(QuicResponseDecoder.fixedBit((byte) 0b00000000)); + } + + @Test + public void testLongPacketType() { + assertEquals(0, QuicResponseDecoder.longPacketType((byte) 0b00000000)); + assertEquals(1, QuicResponseDecoder.longPacketType((byte) 0b00010000)); + assertEquals(2, QuicResponseDecoder.longPacketType((byte) 0b00100000)); + assertEquals(3, QuicResponseDecoder.longPacketType((byte) 0b00110000)); + } +} From 8a6e36f8f54ecaed5d540130fde89bb4e9d5afa0 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 17 Nov 2019 15:14:10 +0900 Subject: [PATCH 09/11] handle version negotiation packet --- .../codec/quic/QuicResponseDecoder.java | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java index 9debe7de49f..e7d5d522d5e 100644 --- a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicResponseDecoder.java @@ -1,6 +1,7 @@ package io.netty.handler.codec.quic; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.socket.DatagramPacket; import io.netty.handler.codec.MessageToMessageDecoder; @@ -17,17 +18,21 @@ public class QuicResponseDecoder extends MessageToMessageDecoder private enum State { INITIAL, HEADER, - DCID_LEN + DCID_LEN, + DCID, + SCID_LEN, + SCID, } private State state = State.INITIAL; + private int dcidLen; + private int scidLen; + private int version; @Override protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List out) throws Exception { final ByteBuf byteBuf = msg.content(); - - switch (state) { case INITIAL: if (!byteBuf.isReadable()) { @@ -53,16 +58,44 @@ protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List 0) { + ByteBuf versionBytBuf = byteBuf.readBytes(4); + logger.info("supported version hexdump: {}", ByteBufUtil.hexDump(versionBytBuf)); + } } out.add(new QuicMessage(ReferenceCountUtil.retain(byteBuf))); From 923e6e148116c28c73b96f5393979e5b5cd847df Mon Sep 17 00:00:00 2001 From: John Date: Sun, 17 Nov 2019 23:11:52 +0900 Subject: [PATCH 10/11] start implementing quic encoder --- .../netty/handler/codec/quic/QuicMessage.java | 2 + .../netty/handler/codec/quic/QuicRequest.java | 54 +++++++++++++++++++ .../codec/quic/QuicRequestEncoder.java | 14 +++++ .../handler/codec/quic/BasicQuicTest.java | 6 ++- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java create mode 100644 codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequestEncoder.java diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java index d906eb46405..a6f3a0b1991 100644 --- a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicMessage.java @@ -5,6 +5,8 @@ public class QuicMessage { ByteBuf byteBuf; + QuicMessage() {} + public QuicMessage(ByteBuf byteBuf) { this.byteBuf = byteBuf; } diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java new file mode 100644 index 00000000000..072f47c6304 --- /dev/null +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java @@ -0,0 +1,54 @@ +package io.netty.handler.codec.quic; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import java.net.InetSocketAddress; + +public class QuicRequest extends QuicMessage { + + private final InetSocketAddress inetSocketAddress; + private final int headerForm; + private final int fixedBit; + private final int longPacketType; + private final int typeSpecificBits; + private final int version; + private final byte[] dcid; + private final byte[] scid; + private final int tokenLength; + private final byte[] packetNumber; + + public QuicRequest(InetSocketAddress inetSocketAddress, int headerForm, int fixedBit, + int longPacketType, int typeSpecificBits, int version, byte[] dcid, byte[] scid, int tokenLength, + byte[] packetNumber) { + this.inetSocketAddress = inetSocketAddress; + this.headerForm = headerForm; + this.fixedBit = fixedBit; + this.longPacketType = longPacketType; + this.typeSpecificBits = typeSpecificBits; + this.version = version; + this.dcid = dcid.clone(); + this.scid = scid.clone(); + this.tokenLength = tokenLength; + this.packetNumber = packetNumber.clone(); + } + + public InetSocketAddress getInetSocketAddress() { + return inetSocketAddress; + } + + @Override + public ByteBuf getByteBuf() { + byte header = (byte) (((headerForm & 0x01) << 7) + ((fixedBit & 0x01) << 6) + ((longPacketType & 0x03) << 5) + (typeSpecificBits & 0x0f)); + System.out.println(header); + return Unpooled.buffer() + .writeByte(header) + .writeInt(version) + .writeByte(dcid.length - 1) + .writeBytes(dcid) + .writeByte(scid.length - 1) + .writeBytes(scid) + .writeByte(tokenLength) + .writeBytes(packetNumber); + } +} diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequestEncoder.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequestEncoder.java new file mode 100644 index 00000000000..c811ae66b3e --- /dev/null +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequestEncoder.java @@ -0,0 +1,14 @@ +package io.netty.handler.codec.quic; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.DatagramPacket; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +public class QuicRequestEncoder extends MessageToMessageEncoder { + @Override + protected void encode(ChannelHandlerContext ctx, QuicRequest msg, List out) throws Exception { + out.add(new DatagramPacket(msg.getByteBuf(), msg.getInetSocketAddress())); + } +} diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java index 0b34b9f6e10..d4e9059009f 100644 --- a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java @@ -76,7 +76,8 @@ public void trySendInitialPacket() throws Exception { result.set(Unpooled.copiedBuffer(res)); latch.countDown(); }); - client.writeAndFlush(new DatagramPacket(byteBuf, remote)).sync(); + client.writeAndFlush(new QuicRequest(remote, 1, 1, 0, 0, + 1, new byte[] {0}, new byte[] {0}, 0, new byte[] {0})).sync(); latch.await(); assertNotNull(result.get()); @@ -88,7 +89,7 @@ public void trySendInitialPacket() throws Exception { @Test public void initialPacket() { final byte[] bytes = ByteBufUtil.decodeHexDump("07ff706cb107568ef7116f5f58a9ed9010"); - System.out.println(ByteBufUtil.prettyHexDump(Unpooled.copiedBuffer(bytes)));; + System.out.println(ByteBufUtil.prettyHexDump(Unpooled.copiedBuffer(bytes))); } private static Channel setupServer(Consumer validator) throws Exception { @@ -134,6 +135,7 @@ protected void initChannel(NioDatagramChannel ch)throws Exception { final ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler()); p.addLast(new QuicResponseDecoder()); + p.addLast(new QuicRequestEncoder()); p.addLast(new SimpleChannelInboundHandler() { @Override protected void messageReceived(ChannelHandlerContext ctx, QuicMessage msg) throws Exception { From 376b9d338a88061069b78bdf42e073bfe44fef3b Mon Sep 17 00:00:00 2001 From: jrhee17 Date: Mon, 18 Nov 2019 01:20:48 +0900 Subject: [PATCH 11/11] implement variable length encoding --- .../netty/handler/codec/quic/QuicRequest.java | 33 +++++++++++++++++ .../handler/codec/quic/BasicQuicTest.java | 11 ------ .../handler/codec/quic/QuicRequestTest.java | 37 +++++++++++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 codec-quic/src/test/java/io/netty/handler/codec/quic/QuicRequestTest.java diff --git a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java index 072f47c6304..8d08c9b3de0 100644 --- a/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java +++ b/codec-quic/src/main/java/io/netty/handler/codec/quic/QuicRequest.java @@ -2,11 +2,15 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; import java.net.InetSocketAddress; public class QuicRequest extends QuicMessage { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicRequest.class); + private final InetSocketAddress inetSocketAddress; private final int headerForm; private final int fixedBit; @@ -49,6 +53,35 @@ public ByteBuf getByteBuf() { .writeByte(scid.length - 1) .writeBytes(scid) .writeByte(tokenLength) + .writeBytes(variableLengthIntegerEncoding(packetNumber.length)) .writeBytes(packetNumber); } + + static byte[] variableLengthIntegerEncoding(long length) { + if (length < 64) { + return new byte[] { (byte) (length & 0xff) }; + } else if (length < 16384) { + return new byte[] { (byte) (((length & 0xff00) >> 8) + 0x40), (byte) (length & 0xff) }; + } else if (length < 1073741823) { + return new byte[] { + (byte) (((length & 0xff000000) >> 24) + 0x80), + (byte) ((length & 0xff0000) >> 16), + (byte) ((length & 0xff00) >> 8), + (byte) (length & 0xff), + }; + } else if (length < 4611686018427387904L) { + return new byte[] { + (byte) (((length & 0xff00000000000000L) >> 56) + 0xc0), + (byte) ((length & 0xff000000000000L) >> 48), + (byte) ((length & 0xff0000000000L) >> 40), + (byte) ((length & 0xff00000000L) >> 32), + (byte) ((length & 0xff000000) >> 24), + (byte) ((length & 0xff0000) >> 16), + (byte) ((length & 0xff00) >> 8), + (byte) (length & 0xff), + }; + } else { + throw new IllegalArgumentException("invalid length: " + length); + } + } } diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java index d4e9059009f..9c3436a8baa 100644 --- a/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/BasicQuicTest.java @@ -61,16 +61,6 @@ public void trySendInitialPacket() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference result = new AtomicReference<>(); - final byte[] headerForm = { - (byte) ((0x80 & 0xff) + (0x40 & 0xff)), - (byte) 0, 0, 0, 0x01, - (byte) 0, 0, 0, 0, - 0, 0, 1, 0 - }; - - final ByteBuf byteBuf = Unpooled.copiedBuffer(headerForm); - System.out.println(ByteBufUtil.prettyHexDump(byteBuf)); - final InetSocketAddress remote = new InetSocketAddress("quic.tech", 4433); final Channel client = getClient(remote, res -> { result.set(Unpooled.copiedBuffer(res)); @@ -83,7 +73,6 @@ public void trySendInitialPacket() throws Exception { assertNotNull(result.get()); client.close().await(); - } @Test diff --git a/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicRequestTest.java b/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicRequestTest.java new file mode 100644 index 00000000000..18c6c6ff15c --- /dev/null +++ b/codec-quic/src/test/java/io/netty/handler/codec/quic/QuicRequestTest.java @@ -0,0 +1,37 @@ +package io.netty.handler.codec.quic; + +import io.netty.buffer.ByteBufUtil; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class QuicRequestTest { + + @Test + public void test1byteEncoding() { + final long length = 37; + final byte[] retval = QuicRequest.variableLengthIntegerEncoding(length); + assertEquals("25", ByteBufUtil.hexDump(retval)); + } + + @Test + public void test2byteEncoding() { + final long length = 15293; + final byte[] retval = QuicRequest.variableLengthIntegerEncoding(length); + assertEquals("7bbd", ByteBufUtil.hexDump(retval)); + } + + @Test + public void test4byteEncoding() { + final long length = 494878333; + final byte[] retval = QuicRequest.variableLengthIntegerEncoding(length); + assertEquals("9d7f3e7d", ByteBufUtil.hexDump(retval)); + } + + @Test + public void test8byteEncoding() { + final long length = 151288809941952652L; + final byte[] retval = QuicRequest.variableLengthIntegerEncoding(length); + assertEquals("c2197c5eff14e88c", ByteBufUtil.hexDump(retval)); + } +}