Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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