Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/quic #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
58 changes: 58 additions & 0 deletions codec-quic/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>5.0.0.Final-SNAPSHOT</version>
</parent>

<artifactId>netty-codec-quic</artifactId>
<packaging>jar</packaging>

<name>Netty/Codec/Quic</name>

<properties>
<javaModuleName>io.netty.codec.quic</javaModuleName>
</properties>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-buffer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-transport</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-codec</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-handler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.netty.handler.codec.quic;

import io.netty.buffer.ByteBuf;

public class QuicMessage {
ByteBuf byteBuf;

QuicMessage() {}

public QuicMessage(ByteBuf byteBuf) {
this.byteBuf = byteBuf;
}

public ByteBuf getByteBuf() {
return byteBuf;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.netty.handler.codec.quic;

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;
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(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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<QuicRequest> {
@Override
protected void encode(ChannelHandlerContext ctx, QuicRequest msg, List<Object> out) throws Exception {
out.add(new DatagramPacket(msg.getByteBuf(), msg.getInetSocketAddress()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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;
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<DatagramPacket> {

private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicResponseDecoder.class);

private enum State {
INITIAL,
HEADER,
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<Object> out) throws Exception {
final ByteBuf byteBuf = msg.content();

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);
version = versionByteBuf.readInt();
logger.info("version: {}", version);
state = State.DCID_LEN;
case DCID_LEN:
if (!byteBuf.isReadable()) {
return;
}
dcidLen = byteBuf.readByte();
logger.info("dcidLen: {}", dcidLen);
state = State.DCID;
case DCID:
if (!byteBuf.isReadable()) {
return;
}
final ByteBuf dcid = byteBuf.readBytes(dcidLen);
logger.info("dcid: {}", dcid);
state = State.SCID_LEN;
case SCID_LEN:
if (!byteBuf.isReadable()) {
return;
}
scidLen = byteBuf.readByte();
logger.info("scidLen: {}", scidLen);
state = State.SCID;
case SCID:
if (!byteBuf.isReadable()) {
return;
}
final ByteBuf scid = byteBuf.readBytes(scidLen);
logger.info("scid: {}", scid);
}

// it will be identified as a Version Negotiation packet based on the Version field having a value of 0
if (version == 0) {
while (byteBuf.readableBytes() > 0) {
ByteBuf versionBytBuf = byteBuf.readBytes(4);
logger.info("supported version hexdump: {}", ByteBufUtil.hexDump(versionBytBuf));
}
}

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;
}
}
Loading