Issue #6728 - QUIC and HTTP/3

- commonalize quiche constants across bindings
This commit is contained in:
Ludovic Orban 2021-11-09 09:18:40 +01:00 committed by Simone Bordet
parent f0eb26533a
commit d2e76b077b
7 changed files with 190 additions and 294 deletions

View File

@ -13,16 +13,109 @@
package org.eclipse.jetty.quic.quiche;
interface Quiche
public interface Quiche
{
// The current QUIC wire version.
int QUICHE_PROTOCOL_VERSION = 0x00000001;
// The maximum length of a connection ID.
int QUICHE_MAX_CONN_ID_LEN = 20;
// The minimum length of Initial packets sent by a client.
int QUICHE_MIN_CLIENT_INITIAL_LEN = 1200;
interface quiche_cc_algorithm
{
int QUICHE_CC_RENO = 0,
QUICHE_CC_CUBIC = 1;
}
interface quiche_error
{
// There is no more work to do.
long QUICHE_ERR_DONE = -1,
// The provided buffer is too short.
QUICHE_ERR_BUFFER_TOO_SHORT = -2,
// The provided packet cannot be parsed because its version is unknown.
QUICHE_ERR_UNKNOWN_VERSION = -3,
// The provided packet cannot be parsed because it contains an invalid
// frame.
QUICHE_ERR_INVALID_FRAME = -4,
// The provided packet cannot be parsed.
QUICHE_ERR_INVALID_PACKET = -5,
// The operation cannot be completed because the connection is in an
// invalid state.
QUICHE_ERR_INVALID_STATE = -6,
// The operation cannot be completed because the stream is in an
// invalid state.
QUICHE_ERR_INVALID_STREAM_STATE = -7,
// The peer's transport params cannot be parsed.
QUICHE_ERR_INVALID_TRANSPORT_PARAM = -8,
// A cryptographic operation failed.
QUICHE_ERR_CRYPTO_FAIL = -9,
// The TLS handshake failed.
QUICHE_ERR_TLS_FAIL = -10,
// The peer violated the local flow control limits.
QUICHE_ERR_FLOW_CONTROL = -11,
// The peer violated the local stream limits.
QUICHE_ERR_STREAM_LIMIT = -12,
// The specified stream was stopped by the peer.
QUICHE_ERR_STREAM_STOPPED = -15,
// The specified stream was reset by the peer.
QUICHE_ERR_STREAM_RESET = -16,
// The received data exceeds the stream's final size.
QUICHE_ERR_FINAL_SIZE = -13,
// Error in congestion control.
QUICHE_ERR_CONGESTION_CONTROL = -14;
static String errToString(long err)
{
if (err == QUICHE_ERR_DONE)
return "QUICHE_ERR_DONE";
if (err == QUICHE_ERR_BUFFER_TOO_SHORT)
return "QUICHE_ERR_BUFFER_TOO_SHORT";
if (err == QUICHE_ERR_UNKNOWN_VERSION)
return "QUICHE_ERR_UNKNOWN_VERSION";
if (err == QUICHE_ERR_INVALID_FRAME)
return "QUICHE_ERR_INVALID_FRAME";
if (err == QUICHE_ERR_INVALID_PACKET)
return "QUICHE_ERR_INVALID_PACKET";
if (err == QUICHE_ERR_INVALID_STATE)
return "QUICHE_ERR_INVALID_STATE";
if (err == QUICHE_ERR_INVALID_STREAM_STATE)
return "QUICHE_ERR_INVALID_STREAM_STATE";
if (err == QUICHE_ERR_INVALID_TRANSPORT_PARAM)
return "QUICHE_ERR_INVALID_TRANSPORT_PARAM";
if (err == QUICHE_ERR_CRYPTO_FAIL)
return "QUICHE_ERR_CRYPTO_FAIL";
if (err == QUICHE_ERR_TLS_FAIL)
return "QUICHE_ERR_TLS_FAIL";
if (err == QUICHE_ERR_FLOW_CONTROL)
return "QUICHE_ERR_FLOW_CONTROL";
if (err == QUICHE_ERR_STREAM_LIMIT)
return "QUICHE_ERR_STREAM_LIMIT";
if (err == QUICHE_ERR_FINAL_SIZE)
return "QUICHE_ERR_FINAL_SIZE";
if (err == QUICHE_ERR_CONGESTION_CONTROL)
return "QUICHE_ERR_CONGESTION_CONTROL";
if (err == QUICHE_ERR_STREAM_STOPPED)
return "QUICHE_ERR_STREAM_STOPPED";
if (err == QUICHE_ERR_STREAM_RESET)
return "QUICHE_ERR_STREAM_RESET";
return "?? " + err;
}
}
}

View File

@ -28,6 +28,7 @@ import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
import org.eclipse.jetty.quic.quiche.Quiche.quiche_error;
import org.eclipse.jetty.quic.quiche.QuicheConfig;
import org.eclipse.jetty.quic.quiche.QuicheConnection;
import org.eclipse.jetty.util.BufferUtil;
@ -35,6 +36,10 @@ import org.eclipse.jetty.util.thread.AutoLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.eclipse.jetty.quic.quiche.Quiche.QUICHE_MAX_CONN_ID_LEN;
import static org.eclipse.jetty.quic.quiche.foreign.incubator.quiche_h.C_FALSE;
import static org.eclipse.jetty.quic.quiche.foreign.incubator.quiche_h.C_TRUE;
public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
private static final Logger LOG = LoggerFactory.getLogger(ForeignIncubatorQuicheConnection.class);
@ -67,12 +72,12 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
MemorySegment version = MemorySegment.allocateNative(CLinker.C_INT, scope);
// Source Connection ID
MemorySegment scid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
scid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(scid.byteSize());
// Destination Connection ID
MemorySegment dcid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(dcid.byteSize());
@ -87,7 +92,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
// If the ByteBuffer is direct, it can be used without any copy.
MemorySegment packetReadSegment = MemorySegment.ofByteBuffer(packet);
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packet.remaining(), quiche_h.QUICHE_MAX_CONN_ID_LEN,
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packet.remaining(), QUICHE_MAX_CONN_ID_LEN,
version.address(), type.address(),
scid.address(), scid_len.address(),
dcid.address(), dcid_len.address(),
@ -100,7 +105,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
int prevPosition = packet.position();
packetReadSegment.asByteBuffer().order(ByteOrder.nativeOrder()).put(packet);
packet.position(prevPosition);
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packet.remaining(), quiche_h.QUICHE_MAX_CONN_ID_LEN,
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packet.remaining(), QUICHE_MAX_CONN_ID_LEN,
version.address(), type.address(),
scid.address(), scid_len.address(),
dcid.address(), dcid_len.address(),
@ -121,13 +126,13 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer) throws IOException
{
return connect(quicheConfig, peer, quiche_h.QUICHE_MAX_CONN_ID_LEN);
return connect(quicheConfig, peer, QUICHE_MAX_CONN_ID_LEN);
}
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
{
if (connectionIdLength > quiche_h.QUICHE_MAX_CONN_ID_LEN)
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + quiche_h.QUICHE_MAX_CONN_ID_LEN);
if (connectionIdLength > QUICHE_MAX_CONN_ID_LEN)
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + QUICHE_MAX_CONN_ID_LEN);
ResourceScope scope = ResourceScope.newSharedScope();
byte[] scidBytes = new byte[connectionIdLength];
SECURE_RANDOM.nextBytes(scidBytes);
@ -148,7 +153,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
Boolean verifyPeer = config.getVerifyPeer();
if (verifyPeer != null)
quiche_h.quiche_config_verify_peer(quicheConfig, verifyPeer ? quiche_h.C_TRUE : quiche_h.C_FALSE);
quiche_h.quiche_config_verify_peer(quicheConfig, verifyPeer ? C_TRUE : C_FALSE);
String certChainPemPath = config.getCertChainPemPath();
if (certChainPemPath != null)
@ -208,7 +213,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
Boolean disableActiveMigration = config.getDisableActiveMigration();
if (disableActiveMigration != null)
quiche_h.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration ? quiche_h.C_TRUE : quiche_h.C_FALSE);
quiche_h.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration ? C_TRUE : C_FALSE);
return quicheConfig;
}
@ -236,12 +241,12 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
MemorySegment version = MemorySegment.allocateNative(CLinker.C_INT, scope);
// Source Connection ID
MemorySegment scid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
scid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(scid.byteSize());
// Destination Connection ID
MemorySegment dcid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(dcid.byteSize());
@ -250,13 +255,13 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
token_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(token.byteSize());
LOG.debug("getting header info (negotiate)...");
int rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), quiche_h.QUICHE_MAX_CONN_ID_LEN,
int rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), QUICHE_MAX_CONN_ID_LEN,
version.address(), type.address(),
scid.address(), scid_len.address(),
dcid.address(), dcid_len.address(),
token.address(), token_len.address());
if (rc < 0)
throw new IOException("failed to parse header: " + quiche_h.quiche_error.errToString(rc));
throw new IOException("failed to parse header: " + quiche_error.errToString(rc));
packetRead.position(packetRead.limit());
LOG.debug("version: {}", version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt());
@ -265,7 +270,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
LOG.debug("dcid len: {}", dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong());
LOG.debug("token len: {}", token_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong());
if (quiche_h.quiche_version_is_supported(version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt()) == quiche_h.C_FALSE)
if (quiche_h.quiche_version_is_supported(version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt()) == C_FALSE)
{
LOG.debug("version negotiation");
@ -283,7 +288,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
long generated = quiche_h.quiche_negotiate_version(scid.address(), scid_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong(), dcid.address(), dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong(), packetToSendSegment.address(), packetToSend.remaining());
if (generated < 0)
throw new IOException("failed to create vneg packet : " + quiche_h.quiche_error.errToString(generated));
throw new IOException("failed to create vneg packet : " + quiche_error.errToString(generated));
if (!packetToSend.isDirect())
packetToSend.put(packetToSendSegment.asByteBuffer().order(ByteOrder.nativeOrder()).limit((int)generated));
else
@ -300,7 +305,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
byte[] tokenBytes = tokenMinter.mint(dcidBytes, dcidBytes.length);
token.asByteBuffer().order(ByteOrder.nativeOrder()).put(tokenBytes);
byte[] newCid = new byte[quiche_h.QUICHE_MAX_CONN_ID_LEN];
byte[] newCid = new byte[QUICHE_MAX_CONN_ID_LEN];
SECURE_RANDOM.nextBytes(newCid);
MemorySegment newCidSegment = MemorySegment.allocateNative(newCid.length, scope);
newCidSegment.asByteBuffer().order(ByteOrder.nativeOrder()).put(newCid);
@ -325,7 +330,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
packetToSendSegment.address(), packetToSendSegment.byteSize()
);
if (generated < 0)
throw new IOException("failed to create retry packet: " + quiche_h.quiche_error.errToString(generated));
throw new IOException("failed to create retry packet: " + quiche_error.errToString(generated));
if (!packetToSend.isDirect())
packetToSend.put(packetToSendSegment.asByteBuffer().order(ByteOrder.nativeOrder()).limit((int)generated));
else
@ -345,12 +350,12 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
MemorySegment version = MemorySegment.allocateNative(CLinker.C_INT, scope);
// Source Connection ID
MemorySegment scid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment scid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
scid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(scid.byteSize());
// Destination Connection ID
MemorySegment dcid = MemorySegment.allocateNative(quiche_h.QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid = MemorySegment.allocateNative(QUICHE_MAX_CONN_ID_LEN, scope);
MemorySegment dcid_len = MemorySegment.allocateNative(CLinker.C_LONG, scope);
dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).putLong(dcid.byteSize());
@ -365,7 +370,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
// If the ByteBuffer is direct, it can be used without any copy.
MemorySegment packetReadSegment = MemorySegment.ofByteBuffer(packetRead);
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), quiche_h.QUICHE_MAX_CONN_ID_LEN,
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), QUICHE_MAX_CONN_ID_LEN,
version.address(), type.address(),
scid.address(), scid_len.address(),
dcid.address(), dcid_len.address(),
@ -380,7 +385,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
int prevPosition = packetRead.position();
packetReadSegment.asByteBuffer().order(ByteOrder.nativeOrder()).put(packetRead);
packetRead.position(prevPosition);
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), quiche_h.QUICHE_MAX_CONN_ID_LEN,
rc = quiche_h.quiche_header_info(packetReadSegment.address(), packetRead.remaining(), QUICHE_MAX_CONN_ID_LEN,
version.address(), type.address(),
scid.address(), scid_len.address(),
dcid.address(), dcid_len.address(),
@ -390,7 +395,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
if (rc < 0)
{
scope.close();
throw new IOException("failed to parse header: " + quiche_h.quiche_error.errToString(rc));
throw new IOException("failed to parse header: " + quiche_error.errToString(rc));
}
LOG.debug("version: {}", version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt());
@ -399,7 +404,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
LOG.debug("dcid len: {}", dcid_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong());
LOG.debug("token len: {}", token_len.asByteBuffer().order(ByteOrder.nativeOrder()).getLong());
if (quiche_h.quiche_version_is_supported(version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt()) == quiche_h.C_FALSE)
if (quiche_h.quiche_version_is_supported(version.asByteBuffer().order(ByteOrder.nativeOrder()).getInt()) == C_FALSE)
{
LOG.debug("need version negotiation");
scope.close();
@ -469,7 +474,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
try (ResourceScope scope = ResourceScope.newConfinedScope())
{
MemorySegment streamIdSegment = MemorySegment.allocateNative(CLinker.C_LONG, scope);
while (quiche_h.quiche_stream_iter_next(quiche_stream_iter, streamIdSegment.address()) != quiche_h.C_FALSE)
while (quiche_h.quiche_stream_iter_next(quiche_stream_iter, streamIdSegment.address()) != C_FALSE)
{
long streamId = streamIdSegment.asByteBuffer().order(ByteOrder.nativeOrder()).getLong();
result.add(streamId);
@ -510,7 +515,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
}
}
if (received < 0)
throw new IOException("failed to receive packet; err=" + quiche_h.quiche_error.errToString(received));
throw new IOException("failed to receive packet; err=" + quiche_error.errToString(received));
buffer.position((int)(buffer.position() + received));
return (int)received;
}
@ -544,10 +549,10 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
}
}
if (written == quiche_h.quiche_error.QUICHE_ERR_DONE)
if (written == quiche_error.QUICHE_ERR_DONE)
return 0;
if (written < 0L)
throw new IOException("failed to send packet; err=" + quiche_h.quiche_error.errToString(written));
throw new IOException("failed to send packet; err=" + quiche_error.errToString(written));
buffer.position((int)(prevPosition + written));
return (int)written;
}
@ -560,7 +565,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
if (quicheConn == null)
throw new IllegalStateException("connection was released");
return quiche_h.quiche_conn_is_closed(quicheConn) != quiche_h.C_FALSE;
return quiche_h.quiche_conn_is_closed(quicheConn) != C_FALSE;
}
}
@ -571,7 +576,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
if (quicheConn == null)
throw new IllegalStateException("connection was released");
return quiche_h.quiche_conn_is_established(quicheConn) != quiche_h.C_FALSE;
return quiche_h.quiche_conn_is_established(quicheConn) != C_FALSE;
}
}
@ -636,7 +641,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
int rc;
if (reason == null)
{
rc = quiche_h.quiche_conn_close(quicheConn, quiche_h.C_TRUE, error, MemoryAddress.NULL, 0);
rc = quiche_h.quiche_conn_close(quicheConn, C_TRUE, error, MemoryAddress.NULL, 0);
}
else
{
@ -647,16 +652,16 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
reasonSegment.asByteBuffer().order(ByteOrder.nativeOrder()).put(reasonBytes);
int length = reasonBytes.length;
MemoryAddress reasonAddress = reasonSegment.address();
rc = quiche_h.quiche_conn_close(quicheConn, quiche_h.C_TRUE, error, reasonAddress, length);
rc = quiche_h.quiche_conn_close(quicheConn, C_TRUE, error, reasonAddress, length);
}
}
if (rc == 0)
return true;
if (rc == quiche_h.quiche_error.QUICHE_ERR_DONE)
if (rc == quiche_error.QUICHE_ERR_DONE)
return false;
if (LOG.isDebugEnabled())
LOG.debug("could not close connection: {}", quiche_h.quiche_error.errToString(rc));
LOG.debug("could not close connection: {}", quiche_error.errToString(rc));
return false;
}
}
@ -690,7 +695,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
if (quicheConn == null)
throw new IllegalStateException("connection was released");
return quiche_h.quiche_conn_is_draining(quicheConn) != quiche_h.C_FALSE;
return quiche_h.quiche_conn_is_draining(quicheConn) != C_FALSE;
}
}
@ -729,7 +734,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
if (value < 0)
{
if (LOG.isDebugEnabled())
LOG.debug("could not read window capacity for stream {} err={}", streamId, quiche_h.quiche_error.errToString(value));
LOG.debug("could not read window capacity for stream {} err={}", streamId, quiche_error.errToString(value));
}
return value;
}
@ -744,9 +749,9 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
throw new IOException("connection was released");
int direction = writeSide ? quiche_h.quiche_shutdown.QUICHE_SHUTDOWN_WRITE : quiche_h.quiche_shutdown.QUICHE_SHUTDOWN_READ;
int rc = quiche_h.quiche_conn_stream_shutdown(quicheConn, streamId, direction, error);
if (rc == 0 || rc == quiche_h.quiche_error.QUICHE_ERR_DONE)
if (rc == 0 || rc == quiche_error.QUICHE_ERR_DONE)
return;
throw new IOException("failed to shutdown stream " + streamId + ": " + quiche_h.quiche_error.errToString(rc));
throw new IOException("failed to shutdown stream " + streamId + ": " + quiche_error.errToString(rc));
}
}
@ -763,7 +768,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
// If the ByteBuffer is direct, it can be used without any copy.
MemorySegment bufferSegment = MemorySegment.ofByteBuffer(buffer);
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment.address(), buffer.remaining(), last ? quiche_h.C_TRUE : quiche_h.C_FALSE);
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment.address(), buffer.remaining(), last ? C_TRUE : C_FALSE);
}
else
{
@ -772,7 +777,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
if (buffer.remaining() == 0)
{
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, MemoryAddress.NULL, 0, last ? quiche_h.C_TRUE : quiche_h.C_FALSE);
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, MemoryAddress.NULL, 0, last ? C_TRUE : C_FALSE);
}
else
{
@ -780,15 +785,15 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
int prevPosition = buffer.position();
bufferSegment.asByteBuffer().order(ByteOrder.nativeOrder()).put(buffer);
buffer.position(prevPosition);
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment.address(), buffer.remaining(), last ? quiche_h.C_TRUE : quiche_h.C_FALSE);
written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment.address(), buffer.remaining(), last ? C_TRUE : C_FALSE);
}
}
}
if (written == quiche_h.quiche_error.QUICHE_ERR_DONE)
if (written == quiche_error.QUICHE_ERR_DONE)
return 0;
if (written < 0L)
throw new IOException("failed to write to stream " + streamId + "; err=" + quiche_h.quiche_error.errToString(written));
throw new IOException("failed to write to stream " + streamId + "; err=" + quiche_error.errToString(written));
buffer.position((int)(buffer.position() + written));
return (int)written;
}
@ -826,10 +831,10 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
}
}
if (read == quiche_h.quiche_error.QUICHE_ERR_DONE)
if (read == quiche_error.QUICHE_ERR_DONE)
return isStreamFinished(streamId) ? -1 : 0;
if (read < 0L)
throw new IOException("failed to read from stream " + streamId + "; err=" + quiche_h.quiche_error.errToString(read));
throw new IOException("failed to read from stream " + streamId + "; err=" + quiche_error.errToString(read));
buffer.position((int)(buffer.position() + read));
return (int)read;
}
@ -842,7 +847,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
{
if (quicheConn == null)
throw new IllegalStateException("connection was released");
return quiche_h.quiche_conn_stream_finished(quicheConn, streamId) != quiche_h.C_FALSE;
return quiche_h.quiche_conn_stream_finished(quicheConn, streamId) != C_FALSE;
}
}
@ -859,7 +864,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
MemorySegment error = MemorySegment.allocateNative(CLinker.C_LONG, scope);
MemorySegment reason = MemorySegment.allocateNative(CLinker.C_POINTER, scope);
MemorySegment reasonLength = MemorySegment.allocateNative(CLinker.C_LONG, scope);
if (quiche_h.quiche_conn_peer_error(quicheConn, app.address(), error.address(), reason.address(), reasonLength.address()) != quiche_h.C_FALSE)
if (quiche_h.quiche_conn_peer_error(quicheConn, app.address(), error.address(), reason.address(), reasonLength.address()) != C_FALSE)
{
long errorValue = error.asByteBuffer().order(ByteOrder.nativeOrder()).getLong();
long reasonLengthValue = reasonLength.asByteBuffer().order(ByteOrder.nativeOrder()).getLong();

View File

@ -322,113 +322,12 @@ public class quiche_h
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER)
);
public interface quiche_error
{
// There is no more work to do.
long QUICHE_ERR_DONE = -1,
// The provided buffer is too short.
QUICHE_ERR_BUFFER_TOO_SHORT = -2,
// The provided packet cannot be parsed because its version is unknown.
QUICHE_ERR_UNKNOWN_VERSION = -3,
// The provided packet cannot be parsed because it contains an invalid
// frame.
QUICHE_ERR_INVALID_FRAME = -4,
// The provided packet cannot be parsed.
QUICHE_ERR_INVALID_PACKET = -5,
// The operation cannot be completed because the connection is in an
// invalid state.
QUICHE_ERR_INVALID_STATE = -6,
// The operation cannot be completed because the stream is in an
// invalid state.
QUICHE_ERR_INVALID_STREAM_STATE = -7,
// The peer's transport params cannot be parsed.
QUICHE_ERR_INVALID_TRANSPORT_PARAM = -8,
// A cryptographic operation failed.
QUICHE_ERR_CRYPTO_FAIL = -9,
// The TLS handshake failed.
QUICHE_ERR_TLS_FAIL = -10,
// The peer violated the local flow control limits.
QUICHE_ERR_FLOW_CONTROL = -11,
// The peer violated the local stream limits.
QUICHE_ERR_STREAM_LIMIT = -12,
// The specified stream was stopped by the peer.
QUICHE_ERR_STREAM_STOPPED = -15,
// The specified stream was reset by the peer.
QUICHE_ERR_STREAM_RESET = -16,
// The received data exceeds the stream's final size.
QUICHE_ERR_FINAL_SIZE = -13,
// Error in congestion control.
QUICHE_ERR_CONGESTION_CONTROL = -14;
static String errToString(long err)
{
if (err == QUICHE_ERR_DONE)
return "QUICHE_ERR_DONE";
if (err == QUICHE_ERR_BUFFER_TOO_SHORT)
return "QUICHE_ERR_BUFFER_TOO_SHORT";
if (err == QUICHE_ERR_UNKNOWN_VERSION)
return "QUICHE_ERR_UNKNOWN_VERSION";
if (err == QUICHE_ERR_INVALID_FRAME)
return "QUICHE_ERR_INVALID_FRAME";
if (err == QUICHE_ERR_INVALID_PACKET)
return "QUICHE_ERR_INVALID_PACKET";
if (err == QUICHE_ERR_INVALID_STATE)
return "QUICHE_ERR_INVALID_STATE";
if (err == QUICHE_ERR_INVALID_STREAM_STATE)
return "QUICHE_ERR_INVALID_STREAM_STATE";
if (err == QUICHE_ERR_INVALID_TRANSPORT_PARAM)
return "QUICHE_ERR_INVALID_TRANSPORT_PARAM";
if (err == QUICHE_ERR_CRYPTO_FAIL)
return "QUICHE_ERR_CRYPTO_FAIL";
if (err == QUICHE_ERR_TLS_FAIL)
return "QUICHE_ERR_TLS_FAIL";
if (err == QUICHE_ERR_FLOW_CONTROL)
return "QUICHE_ERR_FLOW_CONTROL";
if (err == QUICHE_ERR_STREAM_LIMIT)
return "QUICHE_ERR_STREAM_LIMIT";
if (err == QUICHE_ERR_FINAL_SIZE)
return "QUICHE_ERR_FINAL_SIZE";
if (err == QUICHE_ERR_CONGESTION_CONTROL)
return "QUICHE_ERR_CONGESTION_CONTROL";
if (err == QUICHE_ERR_STREAM_STOPPED)
return "QUICHE_ERR_STREAM_STOPPED";
if (err == QUICHE_ERR_STREAM_RESET)
return "QUICHE_ERR_STREAM_RESET";
return "?? " + err;
}
}
public interface quiche_shutdown
{
int QUICHE_SHUTDOWN_READ = 0,
QUICHE_SHUTDOWN_WRITE = 1;
}
public interface quiche_cc_algorithm
{
int QUICHE_CC_RENO = 0,
QUICHE_CC_CUBIC = 1;
}
public static int QUICHE_MIN_CLIENT_INITIAL_LEN = 1200;
public static int QUICHE_MAX_CONN_ID_LEN = 20;
public static int QUICHE_PROTOCOL_VERSION = 0x00000001;
public static MemoryAddress quiche_config_new(int version)
{
try

View File

@ -33,6 +33,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.eclipse.jetty.quic.quiche.Quiche.QUICHE_MIN_CLIENT_INITIAL_LEN;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@ -187,7 +188,7 @@ public class LowLevelQuicheTest
{
ForeignIncubatorQuicheConnection clientQuicheConnection = entry.getKey();
ForeignIncubatorQuicheConnection serverQuicheConnection = entry.getValue();
ByteBuffer buffer = ByteBuffer.allocate(quiche_h.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
int drained = serverQuicheConnection.drainCipherBytes(buffer);
assertThat(drained, is(expectedSize));
@ -200,7 +201,7 @@ public class LowLevelQuicheTest
{
ForeignIncubatorQuicheConnection clientQuicheConnection = entry.getKey();
ForeignIncubatorQuicheConnection serverQuicheConnection = entry.getValue();
ByteBuffer buffer = ByteBuffer.allocate(quiche_h.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
int drained = clientQuicheConnection.drainCipherBytes(buffer);
assertThat(drained, is(expectedSize));
@ -211,8 +212,8 @@ public class LowLevelQuicheTest
private Map.Entry<ForeignIncubatorQuicheConnection, ForeignIncubatorQuicheConnection> connectClientToServer() throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(quiche_h.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer2 = ByteBuffer.allocate(quiche_h.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
ForeignIncubatorQuicheConnection clientQuicheConnection = ForeignIncubatorQuicheConnection.connect(clientQuicheConfig, serverSocketAddress);
connectionsToDisposeOf.add(clientQuicheConnection);

View File

@ -22,6 +22,7 @@ import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.quic.quiche.Quiche.quiche_error;
import org.eclipse.jetty.quic.quiche.QuicheConfig;
import org.eclipse.jetty.quic.quiche.QuicheConnection;
import org.eclipse.jetty.util.BufferUtil;
@ -29,6 +30,8 @@ import org.eclipse.jetty.util.thread.AutoLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.eclipse.jetty.quic.quiche.Quiche.QUICHE_MAX_CONN_ID_LEN;
public class JnaQuicheConnection extends QuicheConnection
{
private static final Logger LOG = LoggerFactory.getLogger(JnaQuicheConnection.class);
@ -56,18 +59,18 @@ public class JnaQuicheConnection extends QuicheConnection
uint32_t_pointer version = new uint32_t_pointer();
// Source Connection ID
byte[] scid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] scid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer scidLen = new size_t_pointer(scid.length);
// Destination Connection ID
byte[] dcid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] dcid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer dcidLen = new size_t_pointer(dcid.length);
byte[] token = new byte[QuicheConnection.TokenMinter.MAX_TOKEN_LENGTH];
size_t_pointer tokenLen = new size_t_pointer(token.length);
LOG.debug("getting header info (fromPacket)...");
int rc = LibQuiche.INSTANCE.quiche_header_info(packet, new size_t(packet.remaining()), new size_t(LibQuiche.QUICHE_MAX_CONN_ID_LEN),
int rc = LibQuiche.INSTANCE.quiche_header_info(packet, new size_t(packet.remaining()), new size_t(QUICHE_MAX_CONN_ID_LEN),
version, type,
scid, scidLen,
dcid, dcidLen,
@ -98,13 +101,13 @@ public class JnaQuicheConnection extends QuicheConnection
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer) throws IOException
{
return connect(quicheConfig, peer, LibQuiche.QUICHE_MAX_CONN_ID_LEN);
return connect(quicheConfig, peer, QUICHE_MAX_CONN_ID_LEN);
}
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
{
if (connectionIdLength > LibQuiche.QUICHE_MAX_CONN_ID_LEN)
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + LibQuiche.QUICHE_MAX_CONN_ID_LEN);
if (connectionIdLength > QUICHE_MAX_CONN_ID_LEN)
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + QUICHE_MAX_CONN_ID_LEN);
byte[] scid = new byte[connectionIdLength];
SECURE_RANDOM.nextBytes(scid);
LibQuiche.quiche_config libQuicheConfig = buildConfig(quicheConfig);
@ -196,17 +199,17 @@ public class JnaQuicheConnection extends QuicheConnection
uint8_t_pointer type = new uint8_t_pointer();
uint32_t_pointer version = new uint32_t_pointer();
byte[] scid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] scid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer scid_len = new size_t_pointer(scid.length);
byte[] dcid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] dcid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer dcid_len = new size_t_pointer(dcid.length);
byte[] token = new byte[TokenMinter.MAX_TOKEN_LENGTH];
size_t_pointer token_len = new size_t_pointer(token.length);
LOG.debug("getting header info (packetType)...");
int rc = LibQuiche.INSTANCE.quiche_header_info(packet, new size_t(packet.remaining()), new size_t(LibQuiche.QUICHE_MAX_CONN_ID_LEN),
int rc = LibQuiche.INSTANCE.quiche_header_info(packet, new size_t(packet.remaining()), new size_t(QUICHE_MAX_CONN_ID_LEN),
version, type,
scid, scid_len,
dcid, dcid_len,
@ -228,24 +231,24 @@ public class JnaQuicheConnection extends QuicheConnection
uint32_t_pointer version = new uint32_t_pointer();
// Source Connection ID
byte[] scid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] scid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer scid_len = new size_t_pointer(scid.length);
// Destination Connection ID
byte[] dcid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] dcid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer dcid_len = new size_t_pointer(dcid.length);
byte[] token = new byte[TokenMinter.MAX_TOKEN_LENGTH];
size_t_pointer token_len = new size_t_pointer(token.length);
LOG.debug("getting header info (negotiate)...");
int rc = LibQuiche.INSTANCE.quiche_header_info(packetRead, new size_t(packetRead.remaining()), new size_t(LibQuiche.QUICHE_MAX_CONN_ID_LEN),
int rc = LibQuiche.INSTANCE.quiche_header_info(packetRead, new size_t(packetRead.remaining()), new size_t(QUICHE_MAX_CONN_ID_LEN),
version, type,
scid, scid_len,
dcid, dcid_len,
token, token_len);
if (rc < 0)
throw new IOException("failed to parse header: " + LibQuiche.quiche_error.errToString(rc));
throw new IOException("failed to parse header: " + quiche_error.errToString(rc));
packetRead.position(packetRead.limit());
LOG.debug("version: {}", version);
@ -261,7 +264,7 @@ public class JnaQuicheConnection extends QuicheConnection
ssize_t generated = LibQuiche.INSTANCE.quiche_negotiate_version(scid, scid_len.getPointee(), dcid, dcid_len.getPointee(), packetToSend, new size_t(packetToSend.remaining()));
packetToSend.position(packetToSend.position() + generated.intValue());
if (generated.intValue() < 0)
throw new IOException("failed to create vneg packet : " + LibQuiche.quiche_error.errToString(generated.intValue()));
throw new IOException("failed to create vneg packet : " + quiche_error.errToString(generated.intValue()));
return true;
}
@ -271,7 +274,7 @@ public class JnaQuicheConnection extends QuicheConnection
token = tokenMinter.mint(dcid, (int)dcid_len.getValue());
byte[] newCid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] newCid = new byte[QUICHE_MAX_CONN_ID_LEN];
SECURE_RANDOM.nextBytes(newCid);
ssize_t generated = LibQuiche.INSTANCE.quiche_retry(scid, scid_len.getPointee(),
@ -283,7 +286,7 @@ public class JnaQuicheConnection extends QuicheConnection
);
packetToSend.position(packetToSend.position() + generated.intValue());
if (generated.intValue() < 0)
throw new IOException("failed to create retry packet: " + LibQuiche.quiche_error.errToString(generated.intValue()));
throw new IOException("failed to create retry packet: " + quiche_error.errToString(generated.intValue()));
return true;
}
@ -300,24 +303,24 @@ public class JnaQuicheConnection extends QuicheConnection
uint32_t_pointer version = new uint32_t_pointer();
// Source Connection ID
byte[] scid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] scid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer scid_len = new size_t_pointer(scid.length);
// Destination Connection ID
byte[] dcid = new byte[LibQuiche.QUICHE_MAX_CONN_ID_LEN];
byte[] dcid = new byte[QUICHE_MAX_CONN_ID_LEN];
size_t_pointer dcid_len = new size_t_pointer(dcid.length);
byte[] token = new byte[TokenMinter.MAX_TOKEN_LENGTH];
size_t_pointer token_len = new size_t_pointer(token.length);
LOG.debug("getting header info (tryAccept)...");
int rc = LibQuiche.INSTANCE.quiche_header_info(packetRead, new size_t(packetRead.remaining()), new size_t(LibQuiche.QUICHE_MAX_CONN_ID_LEN),
int rc = LibQuiche.INSTANCE.quiche_header_info(packetRead, new size_t(packetRead.remaining()), new size_t(QUICHE_MAX_CONN_ID_LEN),
version, type,
scid, scid_len,
dcid, dcid_len,
token, token_len);
if (rc < 0)
throw new IOException("failed to parse header: " + LibQuiche.quiche_error.errToString(rc));
throw new IOException("failed to parse header: " + quiche_error.errToString(rc));
LOG.debug("version: {}", version);
LOG.debug("type: {}", type);
@ -418,7 +421,7 @@ public class JnaQuicheConnection extends QuicheConnection
info.from_len = s.getSize();
int received = LibQuiche.INSTANCE.quiche_conn_recv(quicheConn, buffer, new size_t(buffer.remaining()), info).intValue();
if (received < 0)
throw new IOException("failed to receive packet; err=" + LibQuiche.quiche_error.errToString(received));
throw new IOException("failed to receive packet; err=" + quiche_error.errToString(received));
buffer.position(buffer.position() + received);
return received;
}
@ -442,10 +445,10 @@ public class JnaQuicheConnection extends QuicheConnection
quiche_send_info.to = new sockaddr_storage();
quiche_send_info.to_len = new size_t(quiche_send_info.to.size());
int written = LibQuiche.INSTANCE.quiche_conn_send(quicheConn, buffer, new size_t(buffer.remaining()), quiche_send_info).intValue();
if (written == LibQuiche.quiche_error.QUICHE_ERR_DONE)
if (written == quiche_error.QUICHE_ERR_DONE)
return 0;
if (written < 0L)
throw new IOException("failed to send packet; err=" + LibQuiche.quiche_error.errToString(written));
throw new IOException("failed to send packet; err=" + quiche_error.errToString(written));
int prevPosition = buffer.position();
buffer.position(prevPosition + written);
return written;
@ -535,10 +538,10 @@ public class JnaQuicheConnection extends QuicheConnection
int rc = LibQuiche.INSTANCE.quiche_conn_close(quicheConn, true, new uint64_t(error), reason, new size_t(length));
if (rc == 0)
return true;
if (rc == LibQuiche.quiche_error.QUICHE_ERR_DONE)
if (rc == quiche_error.QUICHE_ERR_DONE)
return false;
if (LOG.isDebugEnabled())
LOG.debug("could not close connection: {}", LibQuiche.quiche_error.errToString(rc));
LOG.debug("could not close connection: {}", quiche_error.errToString(rc));
return false;
}
}
@ -605,7 +608,7 @@ public class JnaQuicheConnection extends QuicheConnection
if (value < 0)
{
if (LOG.isDebugEnabled())
LOG.debug("could not read window capacity for stream {} err={}", streamId, LibQuiche.quiche_error.errToString(value));
LOG.debug("could not read window capacity for stream {} err={}", streamId, quiche_error.errToString(value));
}
return value;
}
@ -620,9 +623,9 @@ public class JnaQuicheConnection extends QuicheConnection
throw new IOException("connection was released");
int direction = writeSide ? LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_WRITE : LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_READ;
int rc = LibQuiche.INSTANCE.quiche_conn_stream_shutdown(quicheConn, new uint64_t(streamId), direction, new uint64_t(error));
if (rc == 0 || rc == LibQuiche.quiche_error.QUICHE_ERR_DONE)
if (rc == 0 || rc == quiche_error.QUICHE_ERR_DONE)
return;
throw new IOException("failed to shutdown stream " + streamId + ": " + LibQuiche.quiche_error.errToString(rc));
throw new IOException("failed to shutdown stream " + streamId + ": " + quiche_error.errToString(rc));
}
}
@ -634,10 +637,10 @@ public class JnaQuicheConnection extends QuicheConnection
if (quicheConn == null)
throw new IOException("connection was released");
int written = LibQuiche.INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), last).intValue();
if (written == LibQuiche.quiche_error.QUICHE_ERR_DONE)
if (written == quiche_error.QUICHE_ERR_DONE)
return 0;
if (written < 0L)
throw new IOException("failed to write to stream " + streamId + "; err=" + LibQuiche.quiche_error.errToString(written));
throw new IOException("failed to write to stream " + streamId + "; err=" + quiche_error.errToString(written));
buffer.position(buffer.position() + written);
return written;
}
@ -652,10 +655,10 @@ public class JnaQuicheConnection extends QuicheConnection
throw new IOException("connection was released");
bool_pointer fin = new bool_pointer();
int read = LibQuiche.INSTANCE.quiche_conn_stream_recv(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), fin).intValue();
if (read == LibQuiche.quiche_error.QUICHE_ERR_DONE)
if (read == quiche_error.QUICHE_ERR_DONE)
return isStreamFinished(streamId) ? -1 : 0;
if (read < 0L)
throw new IOException("failed to read from stream " + streamId + "; err=" + LibQuiche.quiche_error.errToString(read));
throw new IOException("failed to read from stream " + streamId + "; err=" + quiche_error.errToString(read));
buffer.position(buffer.position() + read);
return read;
}

View File

@ -61,112 +61,6 @@ public interface LibQuiche extends Library
// QUIC transport API.
// The current QUIC wire version.
int QUICHE_PROTOCOL_VERSION = 0x00000001;
// The maximum length of a connection ID.
int QUICHE_MAX_CONN_ID_LEN = 20;
// The minimum length of Initial packets sent by a client.
int QUICHE_MIN_CLIENT_INITIAL_LEN = 1200;
interface quiche_cc_algorithm
{
int QUICHE_CC_RENO = 0,
QUICHE_CC_CUBIC = 1;
}
interface quiche_error
{
// There is no more work to do.
long QUICHE_ERR_DONE = -1,
// The provided buffer is too short.
QUICHE_ERR_BUFFER_TOO_SHORT = -2,
// The provided packet cannot be parsed because its version is unknown.
QUICHE_ERR_UNKNOWN_VERSION = -3,
// The provided packet cannot be parsed because it contains an invalid
// frame.
QUICHE_ERR_INVALID_FRAME = -4,
// The provided packet cannot be parsed.
QUICHE_ERR_INVALID_PACKET = -5,
// The operation cannot be completed because the connection is in an
// invalid state.
QUICHE_ERR_INVALID_STATE = -6,
// The operation cannot be completed because the stream is in an
// invalid state.
QUICHE_ERR_INVALID_STREAM_STATE = -7,
// The peer's transport params cannot be parsed.
QUICHE_ERR_INVALID_TRANSPORT_PARAM = -8,
// A cryptographic operation failed.
QUICHE_ERR_CRYPTO_FAIL = -9,
// The TLS handshake failed.
QUICHE_ERR_TLS_FAIL = -10,
// The peer violated the local flow control limits.
QUICHE_ERR_FLOW_CONTROL = -11,
// The peer violated the local stream limits.
QUICHE_ERR_STREAM_LIMIT = -12,
// The specified stream was stopped by the peer.
QUICHE_ERR_STREAM_STOPPED = -15,
// The specified stream was reset by the peer.
QUICHE_ERR_STREAM_RESET = -16,
// The received data exceeds the stream's final size.
QUICHE_ERR_FINAL_SIZE = -13,
// Error in congestion control.
QUICHE_ERR_CONGESTION_CONTROL = -14;
static String errToString(long err)
{
if (err == QUICHE_ERR_DONE)
return "QUICHE_ERR_DONE";
if (err == QUICHE_ERR_BUFFER_TOO_SHORT)
return "QUICHE_ERR_BUFFER_TOO_SHORT";
if (err == QUICHE_ERR_UNKNOWN_VERSION)
return "QUICHE_ERR_UNKNOWN_VERSION";
if (err == QUICHE_ERR_INVALID_FRAME)
return "QUICHE_ERR_INVALID_FRAME";
if (err == QUICHE_ERR_INVALID_PACKET)
return "QUICHE_ERR_INVALID_PACKET";
if (err == QUICHE_ERR_INVALID_STATE)
return "QUICHE_ERR_INVALID_STATE";
if (err == QUICHE_ERR_INVALID_STREAM_STATE)
return "QUICHE_ERR_INVALID_STREAM_STATE";
if (err == QUICHE_ERR_INVALID_TRANSPORT_PARAM)
return "QUICHE_ERR_INVALID_TRANSPORT_PARAM";
if (err == QUICHE_ERR_CRYPTO_FAIL)
return "QUICHE_ERR_CRYPTO_FAIL";
if (err == QUICHE_ERR_TLS_FAIL)
return "QUICHE_ERR_TLS_FAIL";
if (err == QUICHE_ERR_FLOW_CONTROL)
return "QUICHE_ERR_FLOW_CONTROL";
if (err == QUICHE_ERR_STREAM_LIMIT)
return "QUICHE_ERR_STREAM_LIMIT";
if (err == QUICHE_ERR_FINAL_SIZE)
return "QUICHE_ERR_FINAL_SIZE";
if (err == QUICHE_ERR_CONGESTION_CONTROL)
return "QUICHE_ERR_CONGESTION_CONTROL";
if (err == QUICHE_ERR_STREAM_STOPPED)
return "QUICHE_ERR_STREAM_STOPPED";
if (err == QUICHE_ERR_STREAM_RESET)
return "QUICHE_ERR_STREAM_RESET";
return "?? " + err;
}
}
// Returns a human readable string with the quiche version number.
String quiche_version();

View File

@ -32,6 +32,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.eclipse.jetty.quic.quiche.Quiche.QUICHE_MIN_CLIENT_INITIAL_LEN;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@ -186,7 +187,7 @@ public class LowLevelQuicheTest
{
JnaQuicheConnection clientQuicheConnection = entry.getKey();
JnaQuicheConnection serverQuicheConnection = entry.getValue();
ByteBuffer buffer = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
int drained = serverQuicheConnection.drainCipherBytes(buffer);
assertThat(drained, is(expectedSize));
@ -199,7 +200,7 @@ public class LowLevelQuicheTest
{
JnaQuicheConnection clientQuicheConnection = entry.getKey();
JnaQuicheConnection serverQuicheConnection = entry.getValue();
ByteBuffer buffer = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
int drained = clientQuicheConnection.drainCipherBytes(buffer);
assertThat(drained, is(expectedSize));
@ -210,8 +211,8 @@ public class LowLevelQuicheTest
private Map.Entry<JnaQuicheConnection, JnaQuicheConnection> connectClientToServer() throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer2 = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
JnaQuicheConnection clientQuicheConnection = JnaQuicheConnection.connect(clientQuicheConfig, serverSocketAddress);
connectionsToDisposeOf.add(clientQuicheConnection);