Issue #6728 - QUIC and HTTP/3
- commonalize quiche constants across bindings
This commit is contained in:
parent
f0eb26533a
commit
d2e76b077b
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue