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

Modifies to support quiche 0.14.0 #6

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
8 changes: 6 additions & 2 deletions quiche4j-core/src/main/java/io/quiche4j/ConfigBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,15 @@ public final Config build() {
});

if (null != certChainPath) {
Native.quiche_config_load_cert_chain_from_pem_file(pointer, certChainPath);
if(Native.quiche_config_load_cert_chain_from_pem_file(pointer, certChainPath) != 0) {
throw new SecurityException("Cannot load certChain: " + certChainPath);
}
}

if (null != privKeyPath) {
Native.quiche_config_load_priv_key_from_pem_file(pointer, privKeyPath);
if(Native.quiche_config_load_priv_key_from_pem_file(pointer, privKeyPath) != 0) {
throw new SecurityException("Cannot load privKey: " + privKeyPath);
}
}

if (null != verifyPeer) {
Expand Down
35 changes: 32 additions & 3 deletions quiche4j-core/src/main/java/io/quiche4j/Connection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.quiche4j;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Iterator;

import io.quiche4j.Quiche.Shutdown;
Expand Down Expand Up @@ -43,8 +47,8 @@ public class Connection {
* }
* </pre>
*/
public final int recv(byte[] buf) {
return Native.quiche_conn_recv(getPointer(), buf);
public final int recv(byte[] buf, InetSocketAddress fromAddr) {
return Native.quiche_conn_recv(getPointer(), buf, fromAddr.getAddress().getAddress(), fromAddr.getPort());
}

/**
Expand Down Expand Up @@ -87,8 +91,33 @@ public final int recv(byte[] buf) {
* }
* </pre>
*/
public final int send(byte[] buf, InetSocketAddress[] outAddr) {
byte[] v4Addr = new byte[4];
byte[] v6Addr = new byte[16];
int[] port = new int[1];
boolean[] isV4 = new boolean[1];
int ret = Native.quiche_conn_send(getPointer(), buf, v4Addr, v6Addr, port, isV4);
if(ret == -1 || outAddr == null)
return ret;
else {
try {
if (isV4[0]) {
outAddr[0] = new InetSocketAddress(Inet4Address.getByAddress(v4Addr), port[0]);
}
else {
outAddr[0] = new InetSocketAddress(Inet6Address.getByAddress(v6Addr), port[0]);
}
return ret;
}
catch(UnknownHostException e) {
e.printStackTrace();
return -1;
}
}
}

public final int send(byte[] buf) {
return Native.quiche_conn_send(getPointer(), buf);
return send(buf, null);
}

/**
Expand Down
14 changes: 7 additions & 7 deletions quiche4j-core/src/main/java/io/quiche4j/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public final static Cleanable registerCleaner(Object obj, Runnable action) {

public final static native long quiche_config_new(int version);

public final static native void quiche_config_load_cert_chain_from_pem_file(long config_prt, String path);
public final static native int quiche_config_load_cert_chain_from_pem_file(long config_prt, String path);

public final static native void quiche_config_load_priv_key_from_pem_file(long config_ptr, String path);
public final static native int quiche_config_load_priv_key_from_pem_file(long config_ptr, String path);

public final static native void quiche_config_verify_peer(long config_ptr, boolean v);

Expand Down Expand Up @@ -79,9 +79,9 @@ public final static Cleanable registerCleaner(Object obj, Runnable action) {

// CONNECTION

public final static native long quiche_accept(byte[] scid, byte[] odcid, long config_ptr);
public final static native long quiche_accept(byte[] scid, byte[] odcid, byte[] from_addr, int from_port, long config_ptr);

public final static native long quiche_connect(String server_name, byte[] scid, long config_ptr);
public final static native long quiche_connect(String server_name, byte[] scid, byte[] socket_adr, int port, long config_ptr);

public final static native int quiche_negotiate_version(byte[] scid, byte[] dcid, byte[] buf);

Expand All @@ -91,9 +91,9 @@ public final static native int quiche_retry(
byte[] sourceConnId, byte[] destinationConnId, byte[] newSourceConnId,
byte[] token, int version, byte[] buf);

public final static native int quiche_conn_recv(long conn_ptr, byte[] buf);
public final static native int quiche_conn_recv(long conn_ptr, byte[] buf, byte[] from_addr, int from_port);

public final static native int quiche_conn_send(long conn_ptr, byte[] buf);
public final static native int quiche_conn_send(long conn_ptr, byte[] buf, byte[] out_v4addr, byte[] out_v6adr, int[] out_port, boolean[] out_isv4);

public final static native int quiche_conn_close(long conn_ptr, boolean app, long err, byte[] reason);

Expand Down Expand Up @@ -135,5 +135,5 @@ public final static native int quiche_retry(

// PACKET

public final static native void quiche_header_from_slice(byte[] buf, int dcid_len, PacketHeader holder);
public final static native int quiche_header_from_slice(byte[] buf, int dcid_len, PacketHeader holder);
}
12 changes: 9 additions & 3 deletions quiche4j-core/src/main/java/io/quiche4j/PacketHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,16 @@ public final boolean keyPhase() {
* final PacketHeader hdr = PacketHeader::parse(header, 16)
* </pre>
*/
public final static PacketHeader parse(byte[] buf, int dcidLength) {
public final static PacketHeader parse(byte[] buf, int dcidLength, int errorCode[]) {
final PacketHeader hdr = new PacketHeader();
Native.quiche_header_from_slice(buf, dcidLength, hdr);
return hdr;
int err = Native.quiche_header_from_slice(buf, dcidLength, hdr);
if(err < 0) {
if(errorCode != null && errorCode.length > 0)
errorCode[0] = err;
return null;
}
else
return hdr;
}

public final String toString() {
Expand Down
30 changes: 24 additions & 6 deletions quiche4j-core/src/main/java/io/quiche4j/Quiche.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quiche4j;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
Expand Down Expand Up @@ -94,15 +96,31 @@ public static final class ErrorCode {
*/
public static final short STREAM_LIMIT = -12;

/**
* The specified stream was stopped by the peer.
*
* The error code sent as part of the `STOP_SENDING` frame is provided as
* associated data.
*/
public static final short STREAM_STOPPED = -13;

/**
* The specified stream was reset by the peer.
*
* The error code sent as part of the `RESET_STREAM` frame is provided as
* associated data.
*/
public static final short STREAM_RESET = -14;

/**
* The received data exceeds the stream's final size.
*/
public static final short FINAL_SIZE = -13;
public static final short FINAL_SIZE = -15;

/**
* Error in congestion control.
*/
public static final short CONGESTION_CONTROL = -14;
public static final short CONGESTION_CONTROL = -16;
}

/**
Expand Down Expand Up @@ -255,9 +273,9 @@ public static final int retry(byte[] sourceConnId, byte[] destinationConnId, byt
*
* @throws ConnectionFailureException
*/
public static final Connection accept(byte[] sourceConnId, byte[] originalDestinationConnId, Config config)
public static final Connection accept(byte[] sourceConnId, byte[] originalDestinationConnId, InetSocketAddress fromAddr, Config config)
throws ConnectionFailureException {
final long ptr = Native.quiche_accept(sourceConnId, originalDestinationConnId, config.getPointer());
final long ptr = Native.quiche_accept(sourceConnId, originalDestinationConnId, fromAddr.getAddress().getAddress(), fromAddr.getPort(), config.getPointer());
if (ptr <= ErrorCode.SUCCESS) {
throw new ConnectionFailureException(ptr);
}
Expand All @@ -273,9 +291,9 @@ public static final Connection accept(byte[] sourceConnId, byte[] originalDestin
*
* @throws ConnectionFailureException
*/
public static final Connection connect(String serverName, byte[] connId, Config config)
public static final Connection connect(String serverName, byte[] connId, InetSocketAddress addr, Config config)
throws ConnectionFailureException {
final long ptr = Native.quiche_connect(serverName, connId, config.getPointer());
final long ptr = Native.quiche_connect(serverName, connId, addr.getAddress().getAddress(), addr.getPort(), config.getPointer());
if (ptr <= ErrorCode.SUCCESS) {
throw new ConnectionFailureException(ptr);
}
Expand Down
24 changes: 23 additions & 1 deletion quiche4j-core/src/main/java/io/quiche4j/http3/Http3.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ public final class Http3 {
* <p>This can be passed directly to the {@link ConfigBuilder#withApplicationProtos}
* method when implementing HTTP/3 applications.
*/
public static final byte[] APPLICATION_PROTOCOL = "\u0005h3-29\u0005h3-28\u0005h3-27".getBytes();
public static final byte[] APPLICATION_PROTOCOL = "\u0002h3\u0005h3-29\u0005h3-28\u0005h3-27".getBytes();

/**
* A listing of HTTP3 error codes.
*
* [NOTICE]
* TRANSPORT_ERROR has two states in error code. Upper byte is error code on transport (defined in Quiche.ErrorCode),
* and lower byte is HTTP3 error code. So you must divide it into two error codes by h3Error() and quicheError()
* static methods.
*/
public static final class ErrorCode {
/**
Expand Down Expand Up @@ -83,6 +88,23 @@ public static final class ErrorCode {
* for the operation to complete. The application should retry later on.
*/
public static final short STREAM_BLOCKED = -13;

public static final short SETTINGS_ERROR = -14;
public static final short REQUEST_REJECTED = -15;
public static final short REQUEST_CANCELED = -16;
public static final short REQUEST_INCOMPLETE = -17;
public static final short MESSAGE_ERROR = -18;
public static final short CONNECT_ERROR = -19;
public static final short VERSION_FALLBACK = -20;


public static short h3Error(short code) {
return (byte)(code & 0xff);
}

public static short quicheError(short code) {
return (byte)((code & 0xff00) >> 8);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
package io.quiche4j.examples;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -70,11 +64,11 @@ public static void main(String[] args) throws UnknownHostException, IOException
.build();

final byte[] connId = Quiche.newConnectionId();
final Connection conn = Quiche.connect(uri.getHost(), connId, config);
final Connection conn = Quiche.connect(uri.getHost(), connId, new InetSocketAddress(address, port), config);

int len = 0;
final byte[] buffer = new byte[MAX_DATAGRAM_SIZE];
len = conn.send(buffer);
len = conn.send(buffer, null);
if (len < 0 && len != Quiche.ErrorCode.DONE) {
System.out.println("! handshake init problem " + len);
System.exit(1);
Expand Down Expand Up @@ -105,7 +99,7 @@ public static void main(String[] args) throws UnknownHostException, IOException

// xxx(okachaiev): if we extend `recv` API to deal with optional buf len,
// we could avoid Arrays.copy here
final int read = conn.recv(Arrays.copyOfRange(packet.getData(), packet.getOffset(), recvBytes));
final int read = conn.recv(Arrays.copyOfRange(packet.getData(), packet.getOffset(), recvBytes), (InetSocketAddress) packet.getSocketAddress());
if (read < 0 && read != Quiche.ErrorCode.DONE) {
System.out.println("> conn.recv failed " + read);

Expand All @@ -130,7 +124,7 @@ public void onHeaders(long streamId, List<Http3Header> headers, boolean hasBody)

public void onData(long streamId) {
final int bodyLength = h3c.recvBody(streamId, buffer);
if (bodyLength < 0 && bodyLength != Quiche.ErrorCode.DONE) {
if (bodyLength < 0) {
System.out.println("! recv body failed " + bodyLength);
} else {
System.out.println("< got body " + bodyLength + " bytes for " + streamId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@ public final static class QuicHandshakeHandler extends ChannelInboundHandlerAdap
ChannelHandlerContext ctx;
final Connection connection;
final ChannelPromise handshakePromise;
final InetSocketAddress remoteAddress;

QuicHandshakeHandler(Connection connection, ChannelPromise handshakePromise) {
QuicHandshakeHandler(Connection connection, ChannelPromise handshakePromise, InetSocketAddress remoteAddress) {
this.connection = connection;
this.handshakePromise = handshakePromise;
this.remoteAddress = remoteAddress;
}

@Override
Expand Down Expand Up @@ -121,7 +123,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
final byte[] buf = new byte[buffer.readableBytes()];
buffer.readBytes(buf);
this.connection.recv(buf);
this.connection.recv(buf, this.remoteAddress);
if (this.connection.isClosed()) {
this.handshakePromise.setFailure(HANDSHAKE_FAILURE);
ctx.pipeline().remove(this);
Expand All @@ -143,16 +145,18 @@ public final static class HttpOverQuicHandler extends ChannelDuplexHandler {
private final Http3Config config;
private final Map<Long, ChannelPromise> streamResponseMap;
private final AtomicLong lastStreamId;
private final InetSocketAddress remoteAddress;

ChannelHandlerContext context;
Http3Connection http3Connection;
Http3EventListener listener;

HttpOverQuicHandler(Connection connection, Http3Config config) {
HttpOverQuicHandler(Connection connection, Http3Config config, InetSocketAddress remoteAddress) {
this.connection = connection;
this.config = config;
this.streamResponseMap = PlatformDependent.newConcurrentHashMap();
this.lastStreamId = new AtomicLong(0);
this.remoteAddress = remoteAddress;
}

@Override
Expand Down Expand Up @@ -245,7 +249,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (content.readableBytes() > 0) {
final byte[] buf = new byte[content.readableBytes()];
content.readBytes(buf);
final int read = this.connection.recv(buf);
final int read = this.connection.recv(buf, this.remoteAddress);
if (read > 0) {
while(true) {
final long streamId = http3Connection.poll(this.listener);
Expand Down Expand Up @@ -337,9 +341,9 @@ public Http3ClientInitializer(InetSocketAddress address, String domain, Config c
@Override
protected void initChannel(DatagramChannel ch) throws ConnectionFailureException {
final byte[] connId = Quiche.newConnectionId();
final Connection conn = Quiche.connect(this.domain, connId, this.config);
this.handshaker = new QuicHandshakeHandler(conn, ch.newPromise());
this.httpHandler = new HttpOverQuicHandler(conn, http3config);
final Connection conn = Quiche.connect(this.domain, connId, recipient, this.config);
this.handshaker = new QuicHandshakeHandler(conn, ch.newPromise(), ch.remoteAddress());
this.httpHandler = new HttpOverQuicHandler(conn, http3config, ch.remoteAddress());

ch.pipeline().addLast(
new DatagramEncoder(recipient),
Expand Down
Loading