Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
38e7f1e742
|
@ -53,14 +53,35 @@
|
||||||
<profile>
|
<profile>
|
||||||
<id>jdk17</id>
|
<id>jdk17</id>
|
||||||
<activation>
|
<activation>
|
||||||
<jdk>[17,)</jdk>
|
<jdk>17</jdk>
|
||||||
</activation>
|
</activation>
|
||||||
|
<!--
|
||||||
|
This profile makes sure the Foreign binding is used for tests when running exactly on JDK 17.
|
||||||
|
Older and newer JDKs will revert to the JNA binding.
|
||||||
|
-->
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.quic</groupId>
|
<groupId>org.eclipse.jetty.quic</groupId>
|
||||||
<artifactId>quic-quiche-foreign-incubator</artifactId>
|
<artifactId>quic-quiche-foreign-incubator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Make sure to use the Foreign binding by adding and opening the jdk.incubator.foreign module. -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<argLine>
|
||||||
|
@{argLine}
|
||||||
|
${jetty.surefire.argLine}
|
||||||
|
--add-modules=jdk.incubator.foreign
|
||||||
|
--add-opens jdk.incubator.foreign/jdk.incubator.foreign=ALL-UNNAMED
|
||||||
|
--enable-native-access ALL-UNNAMED
|
||||||
|
</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class ClientQuicConnection extends QuicConnection
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("connecting to {} with protocols {}", remoteAddress, protocols);
|
LOG.debug("connecting to {} with protocols {}", remoteAddress, protocols);
|
||||||
|
|
||||||
QuicheConnection quicheConnection = QuicheConnection.connect(quicheConfig, remoteAddress);
|
QuicheConnection quicheConnection = QuicheConnection.connect(quicheConfig, getEndPoint().getLocalAddress(), remoteAddress);
|
||||||
ClientQuicSession session = new ClientQuicSession(getExecutor(), getScheduler(), getByteBufferPool(), quicheConnection, this, remoteAddress, context);
|
ClientQuicSession session = new ClientQuicSession(getExecutor(), getScheduler(), getByteBufferPool(), quicheConnection, this, remoteAddress, context);
|
||||||
pendingSessions.put(remoteAddress, session);
|
pendingSessions.put(remoteAddress, session);
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
|
|
|
@ -75,6 +75,11 @@ public class QuicClientConnectorConfigurator extends ClientConnector.Configurato
|
||||||
{
|
{
|
||||||
context.put(QuicConfiguration.CONTEXT_KEY, configuration);
|
context.put(QuicConfiguration.CONTEXT_KEY, configuration);
|
||||||
DatagramChannel channel = DatagramChannel.open();
|
DatagramChannel channel = DatagramChannel.open();
|
||||||
|
if (clientConnector.getBindAddress() == null)
|
||||||
|
{
|
||||||
|
// QUIC must know the local address for connection migration, so we must always bind early.
|
||||||
|
channel.bind(null);
|
||||||
|
}
|
||||||
return new ChannelWithAddress(channel, address);
|
return new ChannelWithAddress(channel, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,7 @@ public abstract class QuicSession extends ContainerLifeCycle
|
||||||
int remaining = cipherBufferIn.remaining();
|
int remaining = cipherBufferIn.remaining();
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("feeding {} cipher bytes to {}", remaining, this);
|
LOG.debug("feeding {} cipher bytes to {}", remaining, this);
|
||||||
int accepted = quicheConnection.feedCipherBytes(cipherBufferIn, remoteAddress);
|
int accepted = quicheConnection.feedCipherBytes(cipherBufferIn, getLocalAddress(), remoteAddress);
|
||||||
if (accepted != remaining)
|
if (accepted != remaining)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ public interface Quiche
|
||||||
interface quiche_cc_algorithm
|
interface quiche_cc_algorithm
|
||||||
{
|
{
|
||||||
int QUICHE_CC_RENO = 0,
|
int QUICHE_CC_RENO = 0,
|
||||||
QUICHE_CC_CUBIC = 1;
|
QUICHE_CC_CUBIC = 1,
|
||||||
|
QUICHE_CC_BBR = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface quiche_error
|
interface quiche_error
|
||||||
|
|
|
@ -24,7 +24,7 @@ public interface QuicheBinding
|
||||||
int priority();
|
int priority();
|
||||||
|
|
||||||
byte[] fromPacket(ByteBuffer packet);
|
byte[] fromPacket(ByteBuffer packet);
|
||||||
QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException;
|
QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException;
|
||||||
boolean negotiate(QuicheConnection.TokenMinter tokenMinter, ByteBuffer packetRead, ByteBuffer packetToSend) throws IOException;
|
boolean negotiate(QuicheConnection.TokenMinter tokenMinter, ByteBuffer packetRead, ByteBuffer packetToSend) throws IOException;
|
||||||
QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException;
|
QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ public class QuicheConfig
|
||||||
public enum CongestionControl
|
public enum CongestionControl
|
||||||
{
|
{
|
||||||
RENO(Quiche.quiche_cc_algorithm.QUICHE_CC_RENO),
|
RENO(Quiche.quiche_cc_algorithm.QUICHE_CC_RENO),
|
||||||
CUBIC(Quiche.quiche_cc_algorithm.QUICHE_CC_CUBIC);
|
CUBIC(Quiche.quiche_cc_algorithm.QUICHE_CC_CUBIC),
|
||||||
|
BBR(Quiche.quiche_cc_algorithm.QUICHE_CC_BBR);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
CongestionControl(int value)
|
CongestionControl(int value)
|
||||||
|
@ -46,6 +47,9 @@ public class QuicheConfig
|
||||||
private Long initialMaxStreamsBidi;
|
private Long initialMaxStreamsBidi;
|
||||||
private Long initialMaxStreamsUni;
|
private Long initialMaxStreamsUni;
|
||||||
private Boolean disableActiveMigration;
|
private Boolean disableActiveMigration;
|
||||||
|
private Long maxConnectionWindow;
|
||||||
|
private Long maxStreamWindow;
|
||||||
|
private Long activeConnectionIdLimit;
|
||||||
|
|
||||||
public QuicheConfig()
|
public QuicheConfig()
|
||||||
{
|
{
|
||||||
|
@ -121,6 +125,21 @@ public class QuicheConfig
|
||||||
return disableActiveMigration;
|
return disableActiveMigration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getMaxConnectionWindow()
|
||||||
|
{
|
||||||
|
return maxConnectionWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMaxStreamWindow()
|
||||||
|
{
|
||||||
|
return maxStreamWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getActiveConnectionIdLimit()
|
||||||
|
{
|
||||||
|
return activeConnectionIdLimit;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVersion(int version)
|
public void setVersion(int version)
|
||||||
{
|
{
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
@ -191,4 +210,18 @@ public class QuicheConfig
|
||||||
this.disableActiveMigration = disable;
|
this.disableActiveMigration = disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxConnectionWindow(Long sizeInBytes)
|
||||||
|
{
|
||||||
|
this.maxConnectionWindow = sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxStreamWindow(Long maxStreamWindow)
|
||||||
|
{
|
||||||
|
this.maxStreamWindow = maxStreamWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveConnectionIdLimit(Long activeConnectionIdLimit)
|
||||||
|
{
|
||||||
|
this.activeConnectionIdLimit = activeConnectionIdLimit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,14 +49,14 @@ public abstract class QuicheConnection
|
||||||
LOG.debug("using quiche binding implementation: {}", QUICHE_BINDING.getClass().getName());
|
LOG.debug("using quiche binding implementation: {}", QUICHE_BINDING.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer) throws IOException
|
public static QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return connect(quicheConfig, peer, Quiche.QUICHE_MAX_CONN_ID_LEN);
|
return connect(quicheConfig, local, peer, Quiche.QUICHE_MAX_CONN_ID_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
|
public static QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException
|
||||||
{
|
{
|
||||||
return QUICHE_BINDING.connect(quicheConfig, peer, connectionIdLength);
|
return QUICHE_BINDING.connect(quicheConfig, local, peer, connectionIdLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,9 +73,9 @@ public abstract class QuicheConnection
|
||||||
* Fully consumes the {@code packetRead} buffer if the connection was accepted.
|
* Fully consumes the {@code packetRead} buffer if the connection was accepted.
|
||||||
* @return an established connection if accept succeeded, null if accept failed and negotiation should be tried.
|
* @return an established connection if accept succeeded, null if accept failed and negotiation should be tried.
|
||||||
*/
|
*/
|
||||||
public static QuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException
|
public static QuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return QUICHE_BINDING.tryAccept(quicheConfig, tokenValidator, packetRead, peer);
|
return QUICHE_BINDING.tryAccept(quicheConfig, tokenValidator, packetRead, local, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final List<Long> readableStreamIds()
|
public final List<Long> readableStreamIds()
|
||||||
|
@ -93,11 +93,12 @@ public abstract class QuicheConnection
|
||||||
/**
|
/**
|
||||||
* Read the buffer of cipher text coming from the network.
|
* Read the buffer of cipher text coming from the network.
|
||||||
* @param buffer the buffer to read.
|
* @param buffer the buffer to read.
|
||||||
|
* @param local the local address on which the buffer was received.
|
||||||
* @param peer the address of the peer from which the buffer was received.
|
* @param peer the address of the peer from which the buffer was received.
|
||||||
* @return how many bytes were consumed.
|
* @return how many bytes were consumed.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public abstract int feedCipherBytes(ByteBuffer buffer, SocketAddress peer) throws IOException;
|
public abstract int feedCipherBytes(ByteBuffer buffer, SocketAddress local, SocketAddress peer) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the given buffer with cipher text to be sent.
|
* Fill the given buffer with cipher text to be sent.
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
changed both its API (18) and its name (19), so tests are disabled on JDKs over 17.
|
changed both its API (18) and its name (19), so tests are disabled on JDKs over 17.
|
||||||
Eventually, new Foreign modules for JDKs 18 and 19 should be added.
|
Eventually, new Foreign modules for JDKs 18 and 19 should be added.
|
||||||
-->
|
-->
|
||||||
<id>jdk18+</id>
|
<id>jdk18</id>
|
||||||
<activation>
|
<activation>
|
||||||
<jdk>[18,)</jdk>
|
<jdk>[18,)</jdk>
|
||||||
</activation>
|
</activation>
|
||||||
|
|
|
@ -57,9 +57,9 @@ public class ForeignIncubatorQuicheBinding implements QuicheBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
|
public QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException
|
||||||
{
|
{
|
||||||
return ForeignIncubatorQuicheConnection.connect(quicheConfig, peer, connectionIdLength);
|
return ForeignIncubatorQuicheConnection.connect(quicheConfig, local, peer, connectionIdLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,9 +69,9 @@ public class ForeignIncubatorQuicheBinding implements QuicheBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException
|
public QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return ForeignIncubatorQuicheConnection.tryAccept(quicheConfig, tokenValidator, packetRead, peer);
|
return ForeignIncubatorQuicheConnection.tryAccept(quicheConfig, tokenValidator, packetRead, local, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
private MemorySegment sendInfo;
|
private MemorySegment sendInfo;
|
||||||
private MemorySegment recvInfo;
|
private MemorySegment recvInfo;
|
||||||
private MemorySegment stats;
|
private MemorySegment stats;
|
||||||
|
private MemorySegment pathStats;
|
||||||
|
|
||||||
private ForeignIncubatorQuicheConnection(MemoryAddress quicheConn, MemoryAddress quicheConfig, ResourceScope scope)
|
private ForeignIncubatorQuicheConnection(MemoryAddress quicheConn, MemoryAddress quicheConfig, ResourceScope scope)
|
||||||
{
|
{
|
||||||
|
@ -62,6 +63,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
this.sendInfo = quiche_send_info.allocate(scope);
|
this.sendInfo = quiche_send_info.allocate(scope);
|
||||||
this.recvInfo = quiche_recv_info.allocate(scope);
|
this.recvInfo = quiche_recv_info.allocate(scope);
|
||||||
this.stats = quiche_stats.allocate(scope);
|
this.stats = quiche_stats.allocate(scope);
|
||||||
|
this.pathStats = quiche_path_stats.allocate(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] fromPacket(ByteBuffer packet)
|
public static byte[] fromPacket(ByteBuffer packet)
|
||||||
|
@ -124,12 +126,12 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer) throws IOException
|
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return connect(quicheConfig, peer, QUICHE_MAX_CONN_ID_LEN);
|
return connect(quicheConfig, local, peer, QUICHE_MAX_CONN_ID_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
|
public static ForeignIncubatorQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException
|
||||||
{
|
{
|
||||||
if (connectionIdLength > 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);
|
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + QUICHE_MAX_CONN_ID_LEN);
|
||||||
|
@ -144,8 +146,9 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
scid.asByteBuffer().put(scidBytes);
|
scid.asByteBuffer().put(scidBytes);
|
||||||
MemoryAddress libQuicheConfig = buildConfig(quicheConfig, scope);
|
MemoryAddress libQuicheConfig = buildConfig(quicheConfig, scope);
|
||||||
|
|
||||||
MemorySegment s = sockaddr.convert(peer, scope);
|
MemorySegment localSockaddr = sockaddr.convert(local, scope);
|
||||||
MemoryAddress quicheConn = quiche_h.quiche_connect(CLinker.toCString(peer.getHostName(), scope), scid, scid.byteSize(), s, s.byteSize(), libQuicheConfig);
|
MemorySegment peerSockaddr = sockaddr.convert(peer, scope);
|
||||||
|
MemoryAddress quicheConn = quiche_h.quiche_connect(CLinker.toCString(peer.getHostName(), scope), scid, scid.byteSize(), localSockaddr, localSockaddr.byteSize(), peerSockaddr, peerSockaddr.byteSize(), libQuicheConfig);
|
||||||
ForeignIncubatorQuicheConnection connection = new ForeignIncubatorQuicheConnection(quicheConn, libQuicheConfig, scope);
|
ForeignIncubatorQuicheConnection connection = new ForeignIncubatorQuicheConnection(quicheConn, libQuicheConfig, scope);
|
||||||
keepScope = true;
|
keepScope = true;
|
||||||
return connection;
|
return connection;
|
||||||
|
@ -227,6 +230,18 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
if (disableActiveMigration != null)
|
if (disableActiveMigration != null)
|
||||||
quiche_h.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration ? C_TRUE : C_FALSE);
|
quiche_h.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration ? C_TRUE : C_FALSE);
|
||||||
|
|
||||||
|
Long maxConnectionWindow = config.getMaxConnectionWindow();
|
||||||
|
if (maxConnectionWindow != null)
|
||||||
|
quiche_h.quiche_config_set_max_connection_window(quicheConfig, maxConnectionWindow);
|
||||||
|
|
||||||
|
Long maxStreamWindow = config.getMaxStreamWindow();
|
||||||
|
if (maxStreamWindow != null)
|
||||||
|
quiche_h.quiche_config_set_max_stream_window(quicheConfig, maxStreamWindow);
|
||||||
|
|
||||||
|
Long activeConnectionIdLimit = config.getActiveConnectionIdLimit();
|
||||||
|
if (activeConnectionIdLimit != null)
|
||||||
|
quiche_h.quiche_config_set_active_connection_id_limit(quicheConfig, activeConnectionIdLimit);
|
||||||
|
|
||||||
return quicheConfig;
|
return quicheConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +369,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ForeignIncubatorQuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException
|
public static ForeignIncubatorQuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
boolean keepScope = false;
|
boolean keepScope = false;
|
||||||
ResourceScope scope = ResourceScope.newSharedScope();
|
ResourceScope scope = ResourceScope.newSharedScope();
|
||||||
|
@ -442,8 +457,9 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
LOG.debug("connection creation...");
|
LOG.debug("connection creation...");
|
||||||
MemoryAddress libQuicheConfig = buildConfig(quicheConfig, scope);
|
MemoryAddress libQuicheConfig = buildConfig(quicheConfig, scope);
|
||||||
|
|
||||||
MemorySegment s = sockaddr.convert(peer, scope);
|
MemorySegment localSockaddr = sockaddr.convert(local, scope);
|
||||||
MemoryAddress quicheConn = quiche_h.quiche_accept(dcid.address(), getLong(dcid_len), odcid.address(), odcid.byteSize(), s.address(), s.byteSize(), libQuicheConfig);
|
MemorySegment peerSockaddr = sockaddr.convert(peer, scope);
|
||||||
|
MemoryAddress quicheConn = quiche_h.quiche_accept(dcid.address(), getLong(dcid_len), odcid.address(), odcid.byteSize(), localSockaddr.address(), localSockaddr.byteSize(), peerSockaddr.address(), peerSockaddr.byteSize(), libQuicheConfig);
|
||||||
if (quicheConn == null)
|
if (quicheConn == null)
|
||||||
{
|
{
|
||||||
quiche_h.quiche_config_free(libQuicheConfig);
|
quiche_h.quiche_config_free(libQuicheConfig);
|
||||||
|
@ -455,7 +471,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
LOG.debug("accepted, immediately receiving the same packet - remaining in buffer: {}", packetRead.remaining());
|
LOG.debug("accepted, immediately receiving the same packet - remaining in buffer: {}", packetRead.remaining());
|
||||||
while (packetRead.hasRemaining())
|
while (packetRead.hasRemaining())
|
||||||
{
|
{
|
||||||
quicheConnection.feedCipherBytes(packetRead, peer);
|
quicheConnection.feedCipherBytes(packetRead, local, peer);
|
||||||
}
|
}
|
||||||
keepScope = true;
|
keepScope = true;
|
||||||
return quicheConnection;
|
return quicheConnection;
|
||||||
|
@ -498,7 +514,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int feedCipherBytes(ByteBuffer buffer, SocketAddress peer) throws IOException
|
public int feedCipherBytes(ByteBuffer buffer, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
try (AutoLock ignore = lock.lock())
|
try (AutoLock ignore = lock.lock())
|
||||||
{
|
{
|
||||||
|
@ -508,7 +524,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
long received;
|
long received;
|
||||||
try (ResourceScope scope = ResourceScope.newConfinedScope())
|
try (ResourceScope scope = ResourceScope.newConfinedScope())
|
||||||
{
|
{
|
||||||
quiche_recv_info.setSocketAddress(recvInfo, peer, scope);
|
quiche_recv_info.setSocketAddress(recvInfo, local, peer, scope);
|
||||||
if (buffer.isDirect())
|
if (buffer.isDirect())
|
||||||
{
|
{
|
||||||
// If the ByteBuffer is direct, it can be used without any copy.
|
// If the ByteBuffer is direct, it can be used without any copy.
|
||||||
|
@ -696,6 +712,7 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
sendInfo = null;
|
sendInfo = null;
|
||||||
recvInfo = null;
|
recvInfo = null;
|
||||||
stats = null;
|
stats = null;
|
||||||
|
pathStats = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,8 +746,8 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
||||||
{
|
{
|
||||||
if (quicheConn == null)
|
if (quicheConn == null)
|
||||||
throw new IllegalStateException("connection was released");
|
throw new IllegalStateException("connection was released");
|
||||||
quiche_h.quiche_conn_stats(quicheConn, stats.address());
|
quiche_h.quiche_conn_path_stats(quicheConn, 0L, pathStats.address());
|
||||||
return quiche_stats.get_cwnd(stats);
|
return quiche_path_stats.get_cwnd(pathStats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class quiche_h
|
||||||
{
|
{
|
||||||
// This interface is a translation of the quiche.h header of a specific version.
|
// This interface is a translation of the quiche.h header of a specific version.
|
||||||
// It needs to be reviewed each time the native lib version changes.
|
// It needs to be reviewed each time the native lib version changes.
|
||||||
private static final String EXPECTED_QUICHE_VERSION = "0.12.0";
|
private static final String EXPECTED_QUICHE_VERSION = "0.16.0";
|
||||||
|
|
||||||
public static final byte C_FALSE = 0;
|
public static final byte C_FALSE = 0;
|
||||||
public static final byte C_TRUE = 1;
|
public static final byte C_TRUE = 1;
|
||||||
|
@ -142,6 +142,24 @@ public class quiche_h
|
||||||
FunctionDescriptor.ofVoid(C_POINTER, C_CHAR)
|
FunctionDescriptor.ofVoid(C_POINTER, C_CHAR)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static final MethodHandle quiche_config_set_max_connection_window$MH = downcallHandle(
|
||||||
|
"quiche_config_set_max_connection_window",
|
||||||
|
"(Ljdk/incubator/foreign/MemoryAddress;J)V",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER, C_LONG)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final MethodHandle quiche_config_set_max_stream_window$MH = downcallHandle(
|
||||||
|
"quiche_config_set_max_stream_window",
|
||||||
|
"(Ljdk/incubator/foreign/MemoryAddress;J)V",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER, C_LONG)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final MethodHandle quiche_config_set_active_connection_id_limit$MH = downcallHandle(
|
||||||
|
"quiche_config_set_active_connection_id_limit",
|
||||||
|
"(Ljdk/incubator/foreign/MemoryAddress;J)V",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER, C_LONG)
|
||||||
|
);
|
||||||
|
|
||||||
private static final MethodHandle quiche_config_free$MH = downcallHandle(
|
private static final MethodHandle quiche_config_free$MH = downcallHandle(
|
||||||
"quiche_config_free",
|
"quiche_config_free",
|
||||||
"(Ljdk/incubator/foreign/MemoryAddress;)V",
|
"(Ljdk/incubator/foreign/MemoryAddress;)V",
|
||||||
|
@ -150,8 +168,8 @@ public class quiche_h
|
||||||
|
|
||||||
private static final MethodHandle quiche_connect$MH = downcallHandle(
|
private static final MethodHandle quiche_connect$MH = downcallHandle(
|
||||||
"quiche_connect",
|
"quiche_connect",
|
||||||
"(Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;)Ljdk/incubator/foreign/MemoryAddress;",
|
"(Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;)Ljdk/incubator/foreign/MemoryAddress;",
|
||||||
FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER)
|
FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER)
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final MethodHandle quiche_conn_send$MH = downcallHandle(
|
private static final MethodHandle quiche_conn_send$MH = downcallHandle(
|
||||||
|
@ -174,8 +192,8 @@ public class quiche_h
|
||||||
|
|
||||||
private static final MethodHandle quiche_accept$MH = downcallHandle(
|
private static final MethodHandle quiche_accept$MH = downcallHandle(
|
||||||
"quiche_accept",
|
"quiche_accept",
|
||||||
"(Ljdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;)Ljdk/incubator/foreign/MemoryAddress;",
|
"(Ljdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;)Ljdk/incubator/foreign/MemoryAddress;",
|
||||||
FunctionDescriptor.of(C_POINTER, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER)
|
FunctionDescriptor.of(C_POINTER, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER, C_LONG, C_POINTER)
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final MethodHandle quiche_negotiate_version$MH = downcallHandle(
|
private static final MethodHandle quiche_negotiate_version$MH = downcallHandle(
|
||||||
|
@ -244,6 +262,12 @@ public class quiche_h
|
||||||
FunctionDescriptor.ofVoid(C_POINTER, C_POINTER)
|
FunctionDescriptor.ofVoid(C_POINTER, C_POINTER)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static final MethodHandle quiche_conn_path_stats$MH = downcallHandle(
|
||||||
|
"quiche_conn_path_stats",
|
||||||
|
"(Ljdk/incubator/foreign/MemoryAddress;JLjdk/incubator/foreign/MemoryAddress;)I",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_LONG, C_POINTER)
|
||||||
|
);
|
||||||
|
|
||||||
private static final MethodHandle quiche_conn_stream_finished$MH = downcallHandle(
|
private static final MethodHandle quiche_conn_stream_finished$MH = downcallHandle(
|
||||||
"quiche_conn_stream_finished",
|
"quiche_conn_stream_finished",
|
||||||
"(Ljdk/incubator/foreign/MemoryAddress;J)B",
|
"(Ljdk/incubator/foreign/MemoryAddress;J)B",
|
||||||
|
@ -412,6 +436,42 @@ public class quiche_h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void quiche_config_set_max_connection_window(MemoryAddress config, long v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
quiche_config_set_max_connection_window$MH.invokeExact(config, v);
|
||||||
|
}
|
||||||
|
catch (Throwable ex)
|
||||||
|
{
|
||||||
|
throw new AssertionError("should not reach here", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void quiche_config_set_max_stream_window(MemoryAddress config, long v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
quiche_config_set_max_stream_window$MH.invokeExact(config, v);
|
||||||
|
}
|
||||||
|
catch (Throwable ex)
|
||||||
|
{
|
||||||
|
throw new AssertionError("should not reach here", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void quiche_config_set_active_connection_id_limit(MemoryAddress config, long v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
quiche_config_set_active_connection_id_limit$MH.invokeExact(config, v);
|
||||||
|
}
|
||||||
|
catch (Throwable ex)
|
||||||
|
{
|
||||||
|
throw new AssertionError("should not reach here", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void quiche_config_set_initial_max_data(MemoryAddress config, long v)
|
public static void quiche_config_set_initial_max_data(MemoryAddress config, long v)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -544,11 +604,11 @@ public class quiche_h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MemoryAddress quiche_connect(Addressable server_name, Addressable scid, long scid_len, Addressable to, long to_len, Addressable config)
|
public static MemoryAddress quiche_connect(Addressable server_name, Addressable scid, long scid_len, Addressable local, long local_len, Addressable peer, long peer_len, Addressable config)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (MemoryAddress) quiche_connect$MH.invokeExact(server_name.address(), scid.address(), scid_len, to.address(), to_len, config.address());
|
return (MemoryAddress) quiche_connect$MH.invokeExact(server_name.address(), scid.address(), scid_len, local.address(), local_len, peer.address(), peer_len, config.address());
|
||||||
}
|
}
|
||||||
catch (Throwable ex)
|
catch (Throwable ex)
|
||||||
{
|
{
|
||||||
|
@ -700,6 +760,18 @@ public class quiche_h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int quiche_conn_path_stats(MemoryAddress conn, long idx, MemoryAddress stats)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (int)quiche_conn_path_stats$MH.invokeExact(conn, idx, stats);
|
||||||
|
}
|
||||||
|
catch (Throwable ex)
|
||||||
|
{
|
||||||
|
throw new AssertionError("should not reach here", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void quiche_conn_on_timeout(MemoryAddress conn)
|
public static void quiche_conn_on_timeout(MemoryAddress conn)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -822,12 +894,13 @@ public class quiche_h
|
||||||
|
|
||||||
public static MemoryAddress quiche_accept(MemoryAddress scid, long scid_len,
|
public static MemoryAddress quiche_accept(MemoryAddress scid, long scid_len,
|
||||||
MemoryAddress odcid, long odcid_len,
|
MemoryAddress odcid, long odcid_len,
|
||||||
MemoryAddress from, long from_len,
|
MemoryAddress local, long local_len,
|
||||||
|
MemoryAddress peer, long peer_len,
|
||||||
MemoryAddress config)
|
MemoryAddress config)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (MemoryAddress)quiche_accept$MH.invokeExact(scid, scid_len, odcid, odcid_len, from, from_len, config);
|
return (MemoryAddress)quiche_accept$MH.invokeExact(scid, scid_len, odcid, odcid_len, local, local_len, peer, peer_len, config);
|
||||||
}
|
}
|
||||||
catch (Throwable ex)
|
catch (Throwable ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under the
|
||||||
|
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||||
|
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.quic.quiche.foreign.incubator;
|
||||||
|
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
|
|
||||||
|
import jdk.incubator.foreign.MemoryLayout;
|
||||||
|
import jdk.incubator.foreign.MemorySegment;
|
||||||
|
import jdk.incubator.foreign.ResourceScope;
|
||||||
|
|
||||||
|
import static jdk.incubator.foreign.CLinker.C_CHAR;
|
||||||
|
import static jdk.incubator.foreign.CLinker.C_INT;
|
||||||
|
import static jdk.incubator.foreign.CLinker.C_LONG;
|
||||||
|
import static jdk.incubator.foreign.CLinker.C_SHORT;
|
||||||
|
|
||||||
|
public class quiche_path_stats
|
||||||
|
{
|
||||||
|
private static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
|
||||||
|
MemoryLayout.structLayout( // struct sockaddr_storage
|
||||||
|
C_SHORT.withName("ss_family"),
|
||||||
|
MemoryLayout.sequenceLayout(118, C_CHAR).withName("__ss_padding"),
|
||||||
|
C_LONG.withName("__ss_align")
|
||||||
|
).withName("local_addr"),
|
||||||
|
C_INT.withName("local_addr_len"),
|
||||||
|
MemoryLayout.paddingLayout(32),
|
||||||
|
MemoryLayout.structLayout( // struct sockaddr_storage
|
||||||
|
C_SHORT.withName("ss_family"),
|
||||||
|
MemoryLayout.sequenceLayout(118, C_CHAR).withName("__ss_padding"),
|
||||||
|
C_LONG.withName("__ss_align")
|
||||||
|
).withName("peer_addr"),
|
||||||
|
C_INT.withName("peer_addr_len"),
|
||||||
|
MemoryLayout.paddingLayout(32),
|
||||||
|
C_LONG.withName("validation_state"),
|
||||||
|
C_CHAR.withName("active"),
|
||||||
|
MemoryLayout.paddingLayout(56),
|
||||||
|
C_LONG.withName("recv"),
|
||||||
|
C_LONG.withName("sent"),
|
||||||
|
C_LONG.withName("lost"),
|
||||||
|
C_LONG.withName("retrans"),
|
||||||
|
C_LONG.withName("rtt"),
|
||||||
|
C_LONG.withName("cwnd"),
|
||||||
|
C_LONG.withName("sent_bytes"),
|
||||||
|
C_LONG.withName("recv_bytes"),
|
||||||
|
C_LONG.withName("lost_bytes"),
|
||||||
|
C_LONG.withName("stream_retrans_bytes"),
|
||||||
|
C_LONG.withName("pmtu"),
|
||||||
|
C_LONG.withName("delivery_rate")
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final VarHandle cwnd = LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("cwnd"));
|
||||||
|
|
||||||
|
public static long get_cwnd(MemorySegment stats)
|
||||||
|
{
|
||||||
|
return (long)cwnd.get(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemorySegment allocate(ResourceScope scope)
|
||||||
|
{
|
||||||
|
return MemorySegment.allocateNative(LAYOUT, scope);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,21 +29,29 @@ public class quiche_recv_info
|
||||||
private static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
|
private static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
|
||||||
C_POINTER.withName("from"),
|
C_POINTER.withName("from"),
|
||||||
C_INT.withName("from_len"),
|
C_INT.withName("from_len"),
|
||||||
|
MemoryLayout.paddingLayout(32),
|
||||||
|
C_POINTER.withName("to"),
|
||||||
|
C_INT.withName("to_len"),
|
||||||
MemoryLayout.paddingLayout(32)
|
MemoryLayout.paddingLayout(32)
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final VarHandle from = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("from")));
|
private static final VarHandle from = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("from")));
|
||||||
private static final VarHandle from_len = LAYOUT.varHandle(int.class, MemoryLayout.PathElement.groupElement("from_len"));
|
private static final VarHandle from_len = LAYOUT.varHandle(int.class, MemoryLayout.PathElement.groupElement("from_len"));
|
||||||
|
private static final VarHandle to = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("to")));
|
||||||
|
private static final VarHandle to_len = LAYOUT.varHandle(int.class, MemoryLayout.PathElement.groupElement("to_len"));
|
||||||
|
|
||||||
public static MemorySegment allocate(ResourceScope scope)
|
public static MemorySegment allocate(ResourceScope scope)
|
||||||
{
|
{
|
||||||
return MemorySegment.allocateNative(LAYOUT, scope);
|
return MemorySegment.allocateNative(LAYOUT, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setSocketAddress(MemorySegment recvInfo, SocketAddress peer, ResourceScope scope)
|
public static void setSocketAddress(MemorySegment recvInfo, SocketAddress local, SocketAddress peer, ResourceScope scope)
|
||||||
{
|
{
|
||||||
MemorySegment sockAddrSegment = sockaddr.convert(peer, scope);
|
MemorySegment peerSockAddrSegment = sockaddr.convert(peer, scope);
|
||||||
from.set(recvInfo, sockAddrSegment.address());
|
from.set(recvInfo, peerSockAddrSegment.address());
|
||||||
from_len.set(recvInfo, (int)sockAddrSegment.byteSize());
|
from_len.set(recvInfo, (int)peerSockAddrSegment.byteSize());
|
||||||
|
MemorySegment localSockAddrSegment = sockaddr.convert(local, scope);
|
||||||
|
to.set(recvInfo, localSockAddrSegment.address());
|
||||||
|
to_len.set(recvInfo, (int)localSockAddrSegment.byteSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,15 @@ import static jdk.incubator.foreign.CLinker.C_SHORT;
|
||||||
|
|
||||||
public class quiche_send_info
|
public class quiche_send_info
|
||||||
{
|
{
|
||||||
private static final MemoryLayout LAYOUT = MemoryLayout.structLayout( // struct sockaddr_storage
|
private static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
|
||||||
MemoryLayout.structLayout(
|
MemoryLayout.structLayout( // struct sockaddr_storage
|
||||||
|
C_SHORT.withName("ss_family"),
|
||||||
|
MemoryLayout.sequenceLayout(118, C_CHAR).withName("__ss_padding"),
|
||||||
|
C_LONG.withName("__ss_align")
|
||||||
|
).withName("from"),
|
||||||
|
C_INT.withName("from_len"),
|
||||||
|
MemoryLayout.paddingLayout(32),
|
||||||
|
MemoryLayout.structLayout( // struct sockaddr_storage
|
||||||
C_SHORT.withName("ss_family"),
|
C_SHORT.withName("ss_family"),
|
||||||
MemoryLayout.sequenceLayout(118, C_CHAR).withName("__ss_padding"),
|
MemoryLayout.sequenceLayout(118, C_CHAR).withName("__ss_padding"),
|
||||||
C_LONG.withName("__ss_align")
|
C_LONG.withName("__ss_align")
|
||||||
|
|
|
@ -29,14 +29,11 @@ public class quiche_stats
|
||||||
C_LONG.withName("sent"),
|
C_LONG.withName("sent"),
|
||||||
C_LONG.withName("lost"),
|
C_LONG.withName("lost"),
|
||||||
C_LONG.withName("retrans"),
|
C_LONG.withName("retrans"),
|
||||||
C_LONG.withName("rtt"),
|
|
||||||
C_LONG.withName("cwnd"),
|
|
||||||
C_LONG.withName("sent_bytes"),
|
C_LONG.withName("sent_bytes"),
|
||||||
C_LONG.withName("recv_bytes"),
|
C_LONG.withName("recv_bytes"),
|
||||||
C_LONG.withName("lost_bytes"),
|
C_LONG.withName("lost_bytes"),
|
||||||
C_LONG.withName("stream_retrans_bytes"),
|
C_LONG.withName("stream_retrans_bytes"),
|
||||||
C_LONG.withName("pmtu"),
|
C_LONG.withName("paths_count"),
|
||||||
C_LONG.withName("delivery_rate"),
|
|
||||||
C_LONG.withName("peer_max_idle_timeout"),
|
C_LONG.withName("peer_max_idle_timeout"),
|
||||||
C_LONG.withName("peer_max_udp_payload_size"),
|
C_LONG.withName("peer_max_udp_payload_size"),
|
||||||
C_LONG.withName("peer_initial_max_data"),
|
C_LONG.withName("peer_initial_max_data"),
|
||||||
|
@ -58,14 +55,8 @@ public class quiche_stats
|
||||||
return MemorySegment.allocateNative(LAYOUT, scope);
|
return MemorySegment.allocateNative(LAYOUT, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final VarHandle cwnd = LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("cwnd"));
|
|
||||||
private static final VarHandle peer_initial_max_streams_bidi = LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("peer_initial_max_streams_bidi"));
|
private static final VarHandle peer_initial_max_streams_bidi = LAYOUT.varHandle(long.class, MemoryLayout.PathElement.groupElement("peer_initial_max_streams_bidi"));
|
||||||
|
|
||||||
public static long get_cwnd(MemorySegment stats)
|
|
||||||
{
|
|
||||||
return (long)cwnd.get(stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long get_peer_initial_max_streams_bidi(MemorySegment stats)
|
public static long get_peer_initial_max_streams_bidi(MemorySegment stats)
|
||||||
{
|
{
|
||||||
return (long)peer_initial_max_streams_bidi.get(stats);
|
return (long)peer_initial_max_streams_bidi.get(stats);
|
||||||
|
|
|
@ -193,7 +193,7 @@ public class LowLevelQuicheTest
|
||||||
int drained = serverQuicheConnection.drainCipherBytes(buffer);
|
int drained = serverQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(expectedSize));
|
assertThat(drained, is(expectedSize));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
int fed = clientQuicheConnection.feedCipherBytes(buffer, serverSocketAddress);
|
int fed = clientQuicheConnection.feedCipherBytes(buffer, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(expectedSize));
|
assertThat(fed, is(expectedSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ public class LowLevelQuicheTest
|
||||||
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(expectedSize));
|
assertThat(drained, is(expectedSize));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
int fed = serverQuicheConnection.feedCipherBytes(buffer, clientSocketAddress);
|
int fed = serverQuicheConnection.feedCipherBytes(buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(fed, is(expectedSize));
|
assertThat(fed, is(expectedSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,20 +215,20 @@ public class LowLevelQuicheTest
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
||||||
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
||||||
|
|
||||||
ForeignIncubatorQuicheConnection clientQuicheConnection = ForeignIncubatorQuicheConnection.connect(clientQuicheConfig, serverSocketAddress);
|
ForeignIncubatorQuicheConnection clientQuicheConnection = ForeignIncubatorQuicheConnection.connect(clientQuicheConfig, clientSocketAddress, serverSocketAddress);
|
||||||
connectionsToDisposeOf.add(clientQuicheConnection);
|
connectionsToDisposeOf.add(clientQuicheConnection);
|
||||||
|
|
||||||
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
ForeignIncubatorQuicheConnection serverQuicheConnection = ForeignIncubatorQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, clientSocketAddress);
|
ForeignIncubatorQuicheConnection serverQuicheConnection = ForeignIncubatorQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(serverQuicheConnection, is(nullValue()));
|
assertThat(serverQuicheConnection, is(nullValue()));
|
||||||
boolean negotiated = ForeignIncubatorQuicheConnection.negotiate(tokenMinter, buffer, buffer2);
|
boolean negotiated = ForeignIncubatorQuicheConnection.negotiate(tokenMinter, buffer, buffer2);
|
||||||
assertThat(negotiated, is(true));
|
assertThat(negotiated, is(true));
|
||||||
buffer2.flip();
|
buffer2.flip();
|
||||||
|
|
||||||
int fed = clientQuicheConnection.feedCipherBytes(buffer2, serverSocketAddress);
|
int fed = clientQuicheConnection.feedCipherBytes(buffer2, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(79));
|
assertThat(fed, is(79));
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
@ -236,7 +236,7 @@ public class LowLevelQuicheTest
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
serverQuicheConnection = ForeignIncubatorQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, clientSocketAddress);
|
serverQuicheConnection = ForeignIncubatorQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(serverQuicheConnection, is(not(nullValue())));
|
assertThat(serverQuicheConnection, is(not(nullValue())));
|
||||||
connectionsToDisposeOf.add(serverQuicheConnection);
|
connectionsToDisposeOf.add(serverQuicheConnection);
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ public class LowLevelQuicheTest
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
fed = clientQuicheConnection.feedCipherBytes(buffer, serverSocketAddress);
|
fed = clientQuicheConnection.feedCipherBytes(buffer, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(1200));
|
assertThat(fed, is(1200));
|
||||||
|
|
||||||
assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));
|
assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));
|
||||||
|
|
|
@ -57,9 +57,9 @@ public class JnaQuicheBinding implements QuicheBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
|
public QuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException
|
||||||
{
|
{
|
||||||
return JnaQuicheConnection.connect(quicheConfig, peer, connectionIdLength);
|
return JnaQuicheConnection.connect(quicheConfig, local, peer, connectionIdLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,9 +69,9 @@ public class JnaQuicheBinding implements QuicheBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException
|
public QuicheConnection tryAccept(QuicheConfig quicheConfig, QuicheConnection.TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return JnaQuicheConnection.tryAccept(quicheConfig, tokenValidator, packetRead, peer);
|
return JnaQuicheConnection.tryAccept(quicheConfig, tokenValidator, packetRead, local, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -99,12 +99,12 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
return sizedBuffer;
|
return sizedBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer) throws IOException
|
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
return connect(quicheConfig, peer, QUICHE_MAX_CONN_ID_LEN);
|
return connect(quicheConfig, local, peer, QUICHE_MAX_CONN_ID_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress peer, int connectionIdLength) throws IOException
|
public static JnaQuicheConnection connect(QuicheConfig quicheConfig, InetSocketAddress local, InetSocketAddress peer, int connectionIdLength) throws IOException
|
||||||
{
|
{
|
||||||
if (connectionIdLength > 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);
|
throw new IOException("Connection ID length is too large: " + connectionIdLength + " > " + QUICHE_MAX_CONN_ID_LEN);
|
||||||
|
@ -112,8 +112,9 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
SECURE_RANDOM.nextBytes(scid);
|
SECURE_RANDOM.nextBytes(scid);
|
||||||
LibQuiche.quiche_config libQuicheConfig = buildConfig(quicheConfig);
|
LibQuiche.quiche_config libQuicheConfig = buildConfig(quicheConfig);
|
||||||
|
|
||||||
SizedStructure<sockaddr> s = sockaddr.convert(peer);
|
SizedStructure<sockaddr> localSockaddr = sockaddr.convert(local);
|
||||||
LibQuiche.quiche_conn quicheConn = LibQuiche.INSTANCE.quiche_connect(peer.getHostName(), scid, new size_t(scid.length), s.getStructure(), s.getSize(), libQuicheConfig);
|
SizedStructure<sockaddr> peerSockaddr = sockaddr.convert(peer);
|
||||||
|
LibQuiche.quiche_conn quicheConn = LibQuiche.INSTANCE.quiche_connect(peer.getHostName(), scid, new size_t(scid.length), localSockaddr.getStructure(), localSockaddr.getSize(), peerSockaddr.getStructure(), peerSockaddr.getSize(), libQuicheConfig);
|
||||||
return new JnaQuicheConnection(quicheConn, libQuicheConfig);
|
return new JnaQuicheConnection(quicheConn, libQuicheConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +186,18 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
if (disableActiveMigration != null)
|
if (disableActiveMigration != null)
|
||||||
LibQuiche.INSTANCE.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration);
|
LibQuiche.INSTANCE.quiche_config_set_disable_active_migration(quicheConfig, disableActiveMigration);
|
||||||
|
|
||||||
|
Long maxConnectionWindow = config.getMaxConnectionWindow();
|
||||||
|
if (maxConnectionWindow != null)
|
||||||
|
LibQuiche.INSTANCE.quiche_config_set_max_connection_window(quicheConfig, new uint64_t(maxConnectionWindow));
|
||||||
|
|
||||||
|
Long maxStreamWindow = config.getMaxStreamWindow();
|
||||||
|
if (maxStreamWindow != null)
|
||||||
|
LibQuiche.INSTANCE.quiche_config_set_max_stream_window(quicheConfig, new uint64_t(maxStreamWindow));
|
||||||
|
|
||||||
|
Long activeConnectionIdLimit = config.getActiveConnectionIdLimit();
|
||||||
|
if (activeConnectionIdLimit != null)
|
||||||
|
LibQuiche.INSTANCE.quiche_config_set_active_connection_id_limit(quicheConfig, new uint64_t(activeConnectionIdLimit));
|
||||||
|
|
||||||
return quicheConfig;
|
return quicheConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +310,7 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
* Fully consumes the {@code packetRead} buffer if the connection was accepted.
|
* Fully consumes the {@code packetRead} buffer if the connection was accepted.
|
||||||
* @return an established connection if accept succeeded, null if accept failed and negotiation should be tried.
|
* @return an established connection if accept succeeded, null if accept failed and negotiation should be tried.
|
||||||
*/
|
*/
|
||||||
public static JnaQuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress peer) throws IOException
|
public static JnaQuicheConnection tryAccept(QuicheConfig quicheConfig, TokenValidator tokenValidator, ByteBuffer packetRead, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
uint8_t_pointer type = new uint8_t_pointer();
|
uint8_t_pointer type = new uint8_t_pointer();
|
||||||
uint32_t_pointer version = new uint32_t_pointer();
|
uint32_t_pointer version = new uint32_t_pointer();
|
||||||
|
@ -350,8 +363,9 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
LOG.debug("connection creation...");
|
LOG.debug("connection creation...");
|
||||||
LibQuiche.quiche_config libQuicheConfig = buildConfig(quicheConfig);
|
LibQuiche.quiche_config libQuicheConfig = buildConfig(quicheConfig);
|
||||||
|
|
||||||
SizedStructure<sockaddr> s = sockaddr.convert(peer);
|
SizedStructure<sockaddr> localSockaddr = sockaddr.convert(local);
|
||||||
LibQuiche.quiche_conn quicheConn = LibQuiche.INSTANCE.quiche_accept(dcid, dcid_len.getPointee(), odcid, new size_t(odcid.length), s.getStructure(), s.getSize(), libQuicheConfig);
|
SizedStructure<sockaddr> peerSockaddr = sockaddr.convert(peer);
|
||||||
|
LibQuiche.quiche_conn quicheConn = LibQuiche.INSTANCE.quiche_accept(dcid, dcid_len.getPointee(), odcid, new size_t(odcid.length), localSockaddr.getStructure(), localSockaddr.getSize(), peerSockaddr.getStructure(), peerSockaddr.getSize(), libQuicheConfig);
|
||||||
|
|
||||||
if (quicheConn == null)
|
if (quicheConn == null)
|
||||||
{
|
{
|
||||||
|
@ -364,7 +378,7 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
LOG.debug("accepted, immediately receiving the same packet - remaining in buffer: {}", packetRead.remaining());
|
LOG.debug("accepted, immediately receiving the same packet - remaining in buffer: {}", packetRead.remaining());
|
||||||
while (packetRead.hasRemaining())
|
while (packetRead.hasRemaining())
|
||||||
{
|
{
|
||||||
quicheConnection.feedCipherBytes(packetRead, peer);
|
quicheConnection.feedCipherBytes(packetRead, local, peer);
|
||||||
}
|
}
|
||||||
return quicheConnection;
|
return quicheConnection;
|
||||||
}
|
}
|
||||||
|
@ -400,15 +414,8 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the buffer of cipher text coming from the network.
|
|
||||||
* @param buffer the buffer to read.
|
|
||||||
* @param peer the address of the peer from which the buffer was received.
|
|
||||||
* @return how many bytes were consumed.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int feedCipherBytes(ByteBuffer buffer, SocketAddress peer) throws IOException
|
public int feedCipherBytes(ByteBuffer buffer, SocketAddress local, SocketAddress peer) throws IOException
|
||||||
{
|
{
|
||||||
try (AutoLock ignore = lock.lock())
|
try (AutoLock ignore = lock.lock())
|
||||||
{
|
{
|
||||||
|
@ -416,9 +423,12 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
throw new IOException("Cannot receive when not connected");
|
throw new IOException("Cannot receive when not connected");
|
||||||
|
|
||||||
LibQuiche.quiche_recv_info info = new LibQuiche.quiche_recv_info();
|
LibQuiche.quiche_recv_info info = new LibQuiche.quiche_recv_info();
|
||||||
SizedStructure<sockaddr> s = sockaddr.convert(peer);
|
SizedStructure<sockaddr> localSockaddr = sockaddr.convert(local);
|
||||||
info.from = s.getStructure().byReference();
|
info.to = localSockaddr.getStructure().byReference();
|
||||||
info.from_len = s.getSize();
|
info.to_len = localSockaddr.getSize();
|
||||||
|
SizedStructure<sockaddr> peerSockaddr = sockaddr.convert(peer);
|
||||||
|
info.from = peerSockaddr.getStructure().byReference();
|
||||||
|
info.from_len = peerSockaddr.getSize();
|
||||||
int received = LibQuiche.INSTANCE.quiche_conn_recv(quicheConn, buffer, new size_t(buffer.remaining()), info).intValue();
|
int received = LibQuiche.INSTANCE.quiche_conn_recv(quicheConn, buffer, new size_t(buffer.remaining()), info).intValue();
|
||||||
if (received < 0)
|
if (received < 0)
|
||||||
throw new IOException("failed to receive packet; err=" + quiche_error.errToString(received));
|
throw new IOException("failed to receive packet; err=" + quiche_error.errToString(received));
|
||||||
|
@ -442,6 +452,8 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
throw new IOException("Cannot send when not connected");
|
throw new IOException("Cannot send when not connected");
|
||||||
|
|
||||||
LibQuiche.quiche_send_info quiche_send_info = new LibQuiche.quiche_send_info();
|
LibQuiche.quiche_send_info quiche_send_info = new LibQuiche.quiche_send_info();
|
||||||
|
quiche_send_info.from = new sockaddr_storage();
|
||||||
|
quiche_send_info.from_len = new size_t(quiche_send_info.to.size());
|
||||||
quiche_send_info.to = new sockaddr_storage();
|
quiche_send_info.to = new sockaddr_storage();
|
||||||
quiche_send_info.to_len = new size_t(quiche_send_info.to.size());
|
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();
|
int written = LibQuiche.INSTANCE.quiche_conn_send(quicheConn, buffer, new size_t(buffer.remaining()), quiche_send_info).intValue();
|
||||||
|
@ -591,8 +603,8 @@ public class JnaQuicheConnection extends QuicheConnection
|
||||||
{
|
{
|
||||||
if (quicheConn == null)
|
if (quicheConn == null)
|
||||||
throw new IllegalStateException("connection was released");
|
throw new IllegalStateException("connection was released");
|
||||||
LibQuiche.quiche_stats stats = new LibQuiche.quiche_stats();
|
LibQuiche.quiche_path_stats stats = new LibQuiche.quiche_path_stats();
|
||||||
LibQuiche.INSTANCE.quiche_conn_stats(quicheConn, stats);
|
LibQuiche.INSTANCE.quiche_conn_path_stats(quicheConn, new size_t(0L), stats);
|
||||||
return stats.cwnd.longValue();
|
return stats.cwnd.longValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public interface LibQuiche extends Library
|
||||||
{
|
{
|
||||||
// This interface is a translation of the quiche.h header of a specific version.
|
// This interface is a translation of the quiche.h header of a specific version.
|
||||||
// It needs to be reviewed each time the native lib version changes.
|
// It needs to be reviewed each time the native lib version changes.
|
||||||
String EXPECTED_QUICHE_VERSION = "0.12.0";
|
String EXPECTED_QUICHE_VERSION = "0.16.0";
|
||||||
|
|
||||||
// The charset used to convert java.lang.String to char * and vice versa.
|
// The charset used to convert java.lang.String to char * and vice versa.
|
||||||
Charset CHARSET = StandardCharsets.UTF_8;
|
Charset CHARSET = StandardCharsets.UTF_8;
|
||||||
|
@ -122,6 +122,18 @@ public interface LibQuiche extends Library
|
||||||
// Sets the `disable_active_migration` transport parameter.
|
// Sets the `disable_active_migration` transport parameter.
|
||||||
void quiche_config_set_disable_active_migration(quiche_config config, boolean v);
|
void quiche_config_set_disable_active_migration(quiche_config config, boolean v);
|
||||||
|
|
||||||
|
// Sets the maximum connection window.
|
||||||
|
void quiche_config_set_max_connection_window(quiche_config config, uint64_t v);
|
||||||
|
|
||||||
|
// Sets the maximum stream window.
|
||||||
|
void quiche_config_set_max_stream_window(quiche_config config, uint64_t v);
|
||||||
|
|
||||||
|
// Sets the limit of active connection IDs.
|
||||||
|
void quiche_config_set_active_connection_id_limit(quiche_config config, uint64_t v);
|
||||||
|
|
||||||
|
// Sets the initial stateless reset token. |v| must contain 16 bytes, otherwise the behaviour is undefined.
|
||||||
|
void quiche_config_set_stateless_reset_token(quiche_config config, byte[] v);
|
||||||
|
|
||||||
// Frees the config object.
|
// Frees the config object.
|
||||||
void quiche_config_free(quiche_config config);
|
void quiche_config_free(quiche_config config);
|
||||||
|
|
||||||
|
@ -133,8 +145,8 @@ public interface LibQuiche extends Library
|
||||||
}
|
}
|
||||||
|
|
||||||
@Structure.FieldOrder({
|
@Structure.FieldOrder({
|
||||||
"recv", "sent", "lost", "retrans", "rtt", "cwnd", "sent_bytes", "recv_bytes", "lost_bytes",
|
"recv", "sent", "lost", "retrans", "sent_bytes", "recv_bytes", "lost_bytes",
|
||||||
"stream_retrans_bytes", "pmtu", "delivery_rate", "peer_max_idle_timeout",
|
"stream_retrans_bytes", "paths_count", "peer_max_idle_timeout",
|
||||||
"peer_max_udp_payload_size", "peer_initial_max_data", "peer_initial_max_stream_data_bidi_local",
|
"peer_max_udp_payload_size", "peer_initial_max_data", "peer_initial_max_stream_data_bidi_local",
|
||||||
"peer_initial_max_stream_data_bidi_remote", "peer_initial_max_stream_data_uni",
|
"peer_initial_max_stream_data_bidi_remote", "peer_initial_max_stream_data_uni",
|
||||||
"peer_initial_max_streams_bidi", "peer_initial_max_streams_uni", "peer_ack_delay_exponent",
|
"peer_initial_max_streams_bidi", "peer_initial_max_streams_uni", "peer_ack_delay_exponent",
|
||||||
|
@ -155,16 +167,10 @@ public interface LibQuiche extends Library
|
||||||
// The number of sent QUIC packets with retranmitted data.
|
// The number of sent QUIC packets with retranmitted data.
|
||||||
public size_t retrans;
|
public size_t retrans;
|
||||||
|
|
||||||
// The estimated round-trip time of the connection (in nanoseconds).
|
|
||||||
public uint64_t rtt;
|
|
||||||
|
|
||||||
// The size of the connection's congestion window in bytes.
|
|
||||||
public size_t cwnd;
|
|
||||||
|
|
||||||
// The number of sent bytes.
|
// The number of sent bytes.
|
||||||
public uint64_t sent_bytes;
|
public uint64_t sent_bytes;
|
||||||
|
|
||||||
// The number of recevied bytes.
|
// The number of received bytes.
|
||||||
public uint64_t recv_bytes;
|
public uint64_t recv_bytes;
|
||||||
|
|
||||||
// The number of bytes lost.
|
// The number of bytes lost.
|
||||||
|
@ -173,11 +179,8 @@ public interface LibQuiche extends Library
|
||||||
// The number of stream bytes retransmitted.
|
// The number of stream bytes retransmitted.
|
||||||
public uint64_t stream_retrans_bytes;
|
public uint64_t stream_retrans_bytes;
|
||||||
|
|
||||||
// The current PMTU for the connection.
|
// The number of known paths for the connection.
|
||||||
public size_t pmtu;
|
public size_t paths_count;
|
||||||
|
|
||||||
// The most recent data delivery rate estimate in bytes/s.
|
|
||||||
public uint64_t delivery_rate;
|
|
||||||
|
|
||||||
// The maximum idle timeout.
|
// The maximum idle timeout.
|
||||||
public uint64_t peer_max_idle_timeout;
|
public uint64_t peer_max_idle_timeout;
|
||||||
|
@ -219,6 +222,65 @@ public interface LibQuiche extends Library
|
||||||
public ssize_t peer_max_datagram_frame_size;
|
public ssize_t peer_max_datagram_frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Structure.FieldOrder({
|
||||||
|
"local_addr", "local_addr_len", "peer_addr", "peer_addr_len",
|
||||||
|
"validation_state", "active", "recv", "sent", "lost", "retrans",
|
||||||
|
"rtt", "cwnd", "sent_bytes", "recv_bytes", "lost_bytes",
|
||||||
|
"stream_retrans_bytes", "pmtu", "delivery_rate"
|
||||||
|
})
|
||||||
|
class quiche_path_stats extends Structure
|
||||||
|
{
|
||||||
|
// The local address used by this path.
|
||||||
|
public sockaddr_storage local_addr;
|
||||||
|
public size_t local_addr_len;
|
||||||
|
|
||||||
|
// The peer address seen by this path.
|
||||||
|
public sockaddr_storage peer_addr;
|
||||||
|
public size_t peer_addr_len;
|
||||||
|
|
||||||
|
// The validation state of the path.
|
||||||
|
public ssize_t validation_state;
|
||||||
|
|
||||||
|
// Whether this path is active.
|
||||||
|
public boolean active;
|
||||||
|
|
||||||
|
// The number of QUIC packets received on this path.
|
||||||
|
public size_t recv;
|
||||||
|
|
||||||
|
// The number of QUIC packets sent on this path.
|
||||||
|
public size_t sent;
|
||||||
|
|
||||||
|
// The number of QUIC packets that were lost on this path.
|
||||||
|
public size_t lost;
|
||||||
|
|
||||||
|
// The number of sent QUIC packets with retransmitted data on this path.
|
||||||
|
public size_t retrans;
|
||||||
|
|
||||||
|
// The estimated round-trip time of the path (in nanoseconds).
|
||||||
|
public uint64_t rtt;
|
||||||
|
|
||||||
|
// The size of the path's congestion window in bytes.
|
||||||
|
public size_t cwnd;
|
||||||
|
|
||||||
|
// The number of sent bytes on this path.
|
||||||
|
public uint64_t sent_bytes;
|
||||||
|
|
||||||
|
// The number of received bytes on this path.
|
||||||
|
public uint64_t recv_bytes;
|
||||||
|
|
||||||
|
// The number of bytes lost on this path.
|
||||||
|
public uint64_t lost_bytes;
|
||||||
|
|
||||||
|
// The number of stream bytes retransmitted on this path.
|
||||||
|
public uint64_t stream_retrans_bytes;
|
||||||
|
|
||||||
|
// The current PMTU for the path.
|
||||||
|
public size_t pmtu;
|
||||||
|
|
||||||
|
// The most recent data delivery rate estimate in bytes/s.
|
||||||
|
public uint64_t delivery_rate;
|
||||||
|
}
|
||||||
|
|
||||||
interface LoggingCallback extends Callback
|
interface LoggingCallback extends Callback
|
||||||
{
|
{
|
||||||
void log(String msg, Pointer argp);
|
void log(String msg, Pointer argp);
|
||||||
|
@ -228,7 +290,10 @@ public interface LibQuiche extends Library
|
||||||
int quiche_enable_debug_logging(LoggingCallback cb, Pointer argp);
|
int quiche_enable_debug_logging(LoggingCallback cb, Pointer argp);
|
||||||
|
|
||||||
// Creates a new client-side connection.
|
// Creates a new client-side connection.
|
||||||
quiche_conn quiche_connect(String server_name, byte[] scid, size_t scid_len, sockaddr to, size_t to_len, quiche_config config);
|
quiche_conn quiche_connect(String server_name, byte[] scid, size_t scid_len,
|
||||||
|
sockaddr local, size_t local_len,
|
||||||
|
sockaddr peer, size_t peer_len,
|
||||||
|
quiche_config config);
|
||||||
|
|
||||||
interface packet_type
|
interface packet_type
|
||||||
{
|
{
|
||||||
|
@ -285,7 +350,10 @@ public interface LibQuiche extends Library
|
||||||
uint32_t version, ByteBuffer out, size_t out_len);
|
uint32_t version, ByteBuffer out, size_t out_len);
|
||||||
|
|
||||||
// Creates a new server-side connection.
|
// Creates a new server-side connection.
|
||||||
quiche_conn quiche_accept(byte[] scid, size_t scid_len, byte[] odcid, size_t odcid_len, sockaddr from, size_t from_len, quiche_config config);
|
quiche_conn quiche_accept(byte[] scid, size_t scid_len, byte[] odcid, size_t odcid_len,
|
||||||
|
sockaddr local, size_t local_len,
|
||||||
|
sockaddr peer, size_t peer_len,
|
||||||
|
quiche_config config);
|
||||||
|
|
||||||
// Returns the amount of time until the next timeout event, in milliseconds.
|
// Returns the amount of time until the next timeout event, in milliseconds.
|
||||||
uint64_t quiche_conn_timeout_as_millis(quiche_conn conn);
|
uint64_t quiche_conn_timeout_as_millis(quiche_conn conn);
|
||||||
|
@ -296,22 +364,43 @@ public interface LibQuiche extends Library
|
||||||
// Collects and returns statistics about the connection.
|
// Collects and returns statistics about the connection.
|
||||||
void quiche_conn_stats(quiche_conn conn, quiche_stats out);
|
void quiche_conn_stats(quiche_conn conn, quiche_stats out);
|
||||||
|
|
||||||
@Structure.FieldOrder({"to", "to_len", "at"})
|
// Collects and returns statistics about the specified path for the connection.
|
||||||
|
//
|
||||||
|
// The `idx` argument represent the path's index (also see the `paths_count`
|
||||||
|
// field of `quiche_stats`).
|
||||||
|
int quiche_conn_path_stats(quiche_conn conn, size_t idx, quiche_path_stats out);
|
||||||
|
|
||||||
|
@Structure.FieldOrder({"from", "from_len", "to", "to_len", "at"})
|
||||||
class quiche_send_info extends Structure
|
class quiche_send_info extends Structure
|
||||||
{
|
{
|
||||||
|
// The local address the packet should be sent from.
|
||||||
|
public sockaddr_storage from;
|
||||||
|
public size_t from_len;
|
||||||
|
|
||||||
|
// The remote address the packet should be sent to.
|
||||||
public sockaddr_storage to;
|
public sockaddr_storage to;
|
||||||
public size_t to_len;
|
public size_t to_len;
|
||||||
|
|
||||||
|
// The time to send the packet out.
|
||||||
public timespec at;
|
public timespec at;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a single QUIC packet to be sent to the peer.
|
// Writes a single QUIC packet to be sent to the peer.
|
||||||
ssize_t quiche_conn_send(quiche_conn conn, ByteBuffer out, size_t out_len, quiche_send_info out_info);
|
ssize_t quiche_conn_send(quiche_conn conn, ByteBuffer out, size_t out_len, quiche_send_info out_info);
|
||||||
|
|
||||||
@Structure.FieldOrder({"from", "from_len"})
|
// Returns the size of the send quantum, in bytes.
|
||||||
|
size_t quiche_conn_send_quantum(quiche_conn conn);
|
||||||
|
|
||||||
|
@Structure.FieldOrder({"from", "from_len", "to", "to_len"})
|
||||||
class quiche_recv_info extends Structure
|
class quiche_recv_info extends Structure
|
||||||
{
|
{
|
||||||
|
// The remote address the packet was received from.
|
||||||
public sockaddr.ByReference from;
|
public sockaddr.ByReference from;
|
||||||
public size_t from_len;
|
public size_t from_len;
|
||||||
|
|
||||||
|
// The local address the packet was received on.
|
||||||
|
public sockaddr.ByReference to;
|
||||||
|
public size_t to_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes QUIC packets received from the peer.
|
// Processes QUIC packets received from the peer.
|
||||||
|
|
|
@ -191,7 +191,7 @@ public class LowLevelQuicheTest
|
||||||
int drained = serverQuicheConnection.drainCipherBytes(buffer);
|
int drained = serverQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(expectedSize));
|
assertThat(drained, is(expectedSize));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
int fed = clientQuicheConnection.feedCipherBytes(buffer, serverSocketAddress);
|
int fed = clientQuicheConnection.feedCipherBytes(buffer, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(expectedSize));
|
assertThat(fed, is(expectedSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ public class LowLevelQuicheTest
|
||||||
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(expectedSize));
|
assertThat(drained, is(expectedSize));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
int fed = serverQuicheConnection.feedCipherBytes(buffer, clientSocketAddress);
|
int fed = serverQuicheConnection.feedCipherBytes(buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(fed, is(expectedSize));
|
assertThat(fed, is(expectedSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,20 +213,20 @@ public class LowLevelQuicheTest
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
ByteBuffer buffer = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
||||||
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
ByteBuffer buffer2 = ByteBuffer.allocate(QUICHE_MIN_CLIENT_INITIAL_LEN);
|
||||||
|
|
||||||
JnaQuicheConnection clientQuicheConnection = JnaQuicheConnection.connect(clientQuicheConfig, serverSocketAddress);
|
JnaQuicheConnection clientQuicheConnection = JnaQuicheConnection.connect(clientQuicheConfig, clientSocketAddress, serverSocketAddress);
|
||||||
connectionsToDisposeOf.add(clientQuicheConnection);
|
connectionsToDisposeOf.add(clientQuicheConnection);
|
||||||
|
|
||||||
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
int drained = clientQuicheConnection.drainCipherBytes(buffer);
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
JnaQuicheConnection serverQuicheConnection = JnaQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, clientSocketAddress);
|
JnaQuicheConnection serverQuicheConnection = JnaQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(serverQuicheConnection, is(nullValue()));
|
assertThat(serverQuicheConnection, is(nullValue()));
|
||||||
boolean negotiated = JnaQuicheConnection.negotiate(tokenMinter, buffer, buffer2);
|
boolean negotiated = JnaQuicheConnection.negotiate(tokenMinter, buffer, buffer2);
|
||||||
assertThat(negotiated, is(true));
|
assertThat(negotiated, is(true));
|
||||||
buffer2.flip();
|
buffer2.flip();
|
||||||
|
|
||||||
int fed = clientQuicheConnection.feedCipherBytes(buffer2, serverSocketAddress);
|
int fed = clientQuicheConnection.feedCipherBytes(buffer2, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(79));
|
assertThat(fed, is(79));
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
@ -234,7 +234,7 @@ public class LowLevelQuicheTest
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
serverQuicheConnection = JnaQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, clientSocketAddress);
|
serverQuicheConnection = JnaQuicheConnection.tryAccept(serverQuicheConfig, tokenValidator, buffer, serverSocketAddress, clientSocketAddress);
|
||||||
assertThat(serverQuicheConnection, is(not(nullValue())));
|
assertThat(serverQuicheConnection, is(not(nullValue())));
|
||||||
connectionsToDisposeOf.add(serverQuicheConnection);
|
connectionsToDisposeOf.add(serverQuicheConnection);
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ public class LowLevelQuicheTest
|
||||||
assertThat(drained, is(1200));
|
assertThat(drained, is(1200));
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
|
|
||||||
fed = clientQuicheConnection.feedCipherBytes(buffer, serverSocketAddress);
|
fed = clientQuicheConnection.feedCipherBytes(buffer, clientSocketAddress, serverSocketAddress);
|
||||||
assertThat(fed, is(1200));
|
assertThat(fed, is(1200));
|
||||||
|
|
||||||
assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));
|
assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class ServerQuicConnection extends QuicConnection
|
||||||
{
|
{
|
||||||
ByteBufferPool byteBufferPool = getByteBufferPool();
|
ByteBufferPool byteBufferPool = getByteBufferPool();
|
||||||
// TODO make the token validator configurable
|
// TODO make the token validator configurable
|
||||||
QuicheConnection quicheConnection = QuicheConnection.tryAccept(connector.newQuicheConfig(), new SimpleTokenValidator((InetSocketAddress)remoteAddress), cipherBuffer, remoteAddress);
|
QuicheConnection quicheConnection = QuicheConnection.tryAccept(connector.newQuicheConfig(), new SimpleTokenValidator((InetSocketAddress)remoteAddress), cipherBuffer, getEndPoint().getLocalAddress(), remoteAddress);
|
||||||
if (quicheConnection == null)
|
if (quicheConnection == null)
|
||||||
{
|
{
|
||||||
ByteBuffer negotiationBuffer = byteBufferPool.acquire(getOutputBufferSize(), true);
|
ByteBuffer negotiationBuffer = byteBufferPool.acquire(getOutputBufferSize(), true);
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -84,8 +84,8 @@
|
||||||
<jboss-threads.version>3.5.0.Final</jboss-threads.version>
|
<jboss-threads.version>3.5.0.Final</jboss-threads.version>
|
||||||
<jetty-assembly-descriptors.version>1.1</jetty-assembly-descriptors.version>
|
<jetty-assembly-descriptors.version>1.1</jetty-assembly-descriptors.version>
|
||||||
<jetty.perf-helper.version>1.0.7</jetty.perf-helper.version>
|
<jetty.perf-helper.version>1.0.7</jetty.perf-helper.version>
|
||||||
|
<jetty-quiche-native.version>0.16.0</jetty-quiche-native.version>
|
||||||
<jetty.servlet.api.version>5.0.2</jetty.servlet.api.version>
|
<jetty.servlet.api.version>5.0.2</jetty.servlet.api.version>
|
||||||
<jetty-quiche-native.version>0.12.0</jetty-quiche-native.version>
|
|
||||||
<jetty-test-policy.version>1.2</jetty-test-policy.version>
|
<jetty-test-policy.version>1.2</jetty-test-policy.version>
|
||||||
<jetty.test.version>6.0</jetty.test.version>
|
<jetty.test.version>6.0</jetty.test.version>
|
||||||
<jmh.version>1.35</jmh.version>
|
<jmh.version>1.35</jmh.version>
|
||||||
|
|
Loading…
Reference in New Issue