From f64bc07da30f42244729367c21b0732b1c71a358 Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Mon, 1 Jul 2024 18:37:26 +0200 Subject: [PATCH 1/2] upgrade quiche to version 0.22.0 Signed-off-by: Ludovic Orban --- .../foreign/ForeignQuicheConnection.java | 30 +++++++++++-------- .../jetty/quic/quiche/foreign/quiche_h.java | 14 +++++---- .../quic/quiche/jna/JnaQuicheConnection.java | 6 ++-- .../jetty/quic/quiche/jna/LibQuiche.java | 14 +++++++-- pom.xml | 2 +- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java index 9aa018d0efe4..6d5cd735a93c 100644 --- a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java +++ b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java @@ -853,20 +853,22 @@ public int feedClearBytesForStream(long streamId, ByteBuffer buffer, boolean las throw new IOException("connection was released"); long written; - if (buffer.isDirect()) - { - // If the ByteBuffer is direct, it can be used without any copy. - MemorySegment bufferSegment = MemorySegment.ofBuffer(buffer); - written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment, buffer.remaining(), last); - } - else + try (Arena scope = Arena.ofConfined()) { - // If the ByteBuffer is heap-allocated, it must be copied to native memory. - try (Arena scope = Arena.ofConfined()) + if (buffer.isDirect()) + { + // If the ByteBuffer is direct, it can be used without any copy. + MemorySegment bufferSegment = MemorySegment.ofBuffer(buffer); + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); + written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment, buffer.remaining(), last, outErrorCode); + } + else { + // If the ByteBuffer is heap-allocated, it must be copied to native memory. + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); if (buffer.remaining() == 0) { - written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, MemorySegment.NULL, 0, last); + written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, MemorySegment.NULL, 0, last, outErrorCode); } else { @@ -874,7 +876,7 @@ public int feedClearBytesForStream(long streamId, ByteBuffer buffer, boolean las int prevPosition = buffer.position(); bufferSegment.asByteBuffer().put(buffer); buffer.position(prevPosition); - written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment, buffer.remaining(), last); + written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment, buffer.remaining(), last, outErrorCode); } } } @@ -909,7 +911,8 @@ public int drainClearBytesForStream(long streamId, ByteBuffer buffer) throws IOE // If the ByteBuffer is direct, it can be used without any copy. MemorySegment bufferSegment = MemorySegment.ofBuffer(buffer); MemorySegment fin = scope.allocate(NativeHelper.C_CHAR); - read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin); + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); + read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin, outErrorCode); } else { @@ -917,7 +920,8 @@ public int drainClearBytesForStream(long streamId, ByteBuffer buffer) throws IOE MemorySegment bufferSegment = scope.allocate(buffer.remaining()); MemorySegment fin = scope.allocate(NativeHelper.C_CHAR); - read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin); + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); + read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin, outErrorCode); if (read > 0) { diff --git a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/quiche_h.java b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/quiche_h.java index e55229a8a69d..2125ccfe434a 100644 --- a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/quiche_h.java +++ b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/quiche_h.java @@ -30,7 +30,7 @@ public class quiche_h { - private static final String EXPECTED_QUICHE_VERSION = "0.21.0"; + private static final String EXPECTED_QUICHE_VERSION = "0.22.0"; private static final Logger LOG = LoggerFactory.getLogger(quiche_h.class); private static class LoggingCallback @@ -485,6 +485,7 @@ private static class DowncallHandles C_LONG, C_POINTER, C_LONG, + C_POINTER, C_POINTER )); private static final MethodHandle quiche_conn_stream_send = NativeHelper.downcallHandle( @@ -495,7 +496,8 @@ private static class DowncallHandles C_LONG, C_POINTER, C_LONG, - C_BOOL + C_BOOL, + C_POINTER )); private static final MethodHandle quiche_conn_stream_priority = NativeHelper.downcallHandle( "quiche_conn_stream_priority", @@ -1662,11 +1664,11 @@ public static long quiche_conn_send_quantum_on_path(MemorySegment conn, MemorySe } } - public static long quiche_conn_stream_recv(MemorySegment conn, long stream_id, MemorySegment out, long buf_len, MemorySegment fin) + public static long quiche_conn_stream_recv(MemorySegment conn, long stream_id, MemorySegment out, long buf_len, MemorySegment fin, MemorySegment out_error_code) { try { - return (long)DowncallHandles.quiche_conn_stream_recv.invokeExact(conn, stream_id, out, buf_len, fin); + return (long)DowncallHandles.quiche_conn_stream_recv.invokeExact(conn, stream_id, out, buf_len, fin, out_error_code); } catch (Throwable x) { @@ -1674,11 +1676,11 @@ public static long quiche_conn_stream_recv(MemorySegment conn, long stream_id, M } } - public static long quiche_conn_stream_send(MemorySegment conn, long stream_id, MemorySegment buf, long buf_len, boolean fin) + public static long quiche_conn_stream_send(MemorySegment conn, long stream_id, MemorySegment buf, long buf_len, boolean fin, MemorySegment out_error_code) { try { - return (long)DowncallHandles.quiche_conn_stream_send.invokeExact(conn, stream_id, buf, buf_len, fin); + return (long)DowncallHandles.quiche_conn_stream_send.invokeExact(conn, stream_id, buf, buf_len, fin, out_error_code); } catch (Throwable x) { diff --git a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/JnaQuicheConnection.java b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/JnaQuicheConnection.java index b81021957a2d..ba483c9c33a8 100644 --- a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/JnaQuicheConnection.java +++ b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/JnaQuicheConnection.java @@ -693,7 +693,8 @@ public int feedClearBytesForStream(long streamId, ByteBuffer buffer, boolean las { if (quicheConn == null) throw new IOException("connection was released"); - int written = LibQuiche.INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), jnaBuffer(buffer), new size_t(buffer.remaining()), last).intValue(); + uint64_t_pointer outErrorCode = new uint64_t_pointer(); + int written = LibQuiche.INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), jnaBuffer(buffer), new size_t(buffer.remaining()), last, outErrorCode).intValue(); if (written == quiche_error.QUICHE_ERR_DONE) { int rc = LibQuiche.INSTANCE.quiche_conn_stream_writable(quicheConn, new uint64_t(streamId), new size_t(buffer.remaining())); @@ -745,7 +746,8 @@ public int drainClearBytesForStream(long streamId, ByteBuffer buffer) throws IOE if (quicheConn == null) 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(); + uint64_t_pointer outErrorCode = new uint64_t_pointer(); + int read = LibQuiche.INSTANCE.quiche_conn_stream_recv(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), fin, outErrorCode).intValue(); if (read == quiche_error.QUICHE_ERR_DONE) return isStreamFinished(streamId) ? -1 : 0; if (read == quiche_error.QUICHE_ERR_STREAM_RESET) diff --git a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/LibQuiche.java b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/LibQuiche.java index 98c2a6ee7148..4a71c6a76855 100644 --- a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/LibQuiche.java +++ b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-jna/src/main/java/org/eclipse/jetty/quic/quiche/jna/LibQuiche.java @@ -31,7 +31,7 @@ public interface LibQuiche extends Library { // 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. - String EXPECTED_QUICHE_VERSION = "0.21.0"; + String EXPECTED_QUICHE_VERSION = "0.22.0"; // The charset used to convert java.lang.String to char * and vice versa. Charset CHARSET = StandardCharsets.UTF_8; @@ -540,10 +540,18 @@ int quiche_conn_stream_shutdown(quiche_conn conn, uint64_t stream_id, void quiche_stream_iter_free(quiche_stream_iter iter); // Reads contiguous data from a stream. - ssize_t quiche_conn_stream_recv(quiche_conn conn, uint64_t stream_id, ByteBuffer out, size_t buf_len, bool_pointer fin); + // out_error_code is only set when STREAM_STOPPED or STREAM_RESET are returned. + // Set to the reported error code associated with STOP_SENDING or STREAM_RESET. + ssize_t quiche_conn_stream_recv(quiche_conn conn, uint64_t stream_id, + ByteBuffer out, size_t buf_len, bool_pointer fin, + uint64_t_pointer out_error_code); // Writes data to a stream. - ssize_t quiche_conn_stream_send(quiche_conn conn, uint64_t stream_id, ByteBuffer buf, size_t buf_len, boolean fin); + // out_error_code is only set when STREAM_STOPPED or STREAM_RESET are returned. + // Set to the reported error code associated with STOP_SENDING or STREAM_RESET. + ssize_t quiche_conn_stream_send(quiche_conn conn, uint64_t stream_id, + ByteBuffer buf, size_t buf_len, boolean fin, + uint64_t_pointer out_error_code); // Frees the connection object. void quiche_conn_free(quiche_conn conn); diff --git a/pom.xml b/pom.xml index 9f54960feb9f..e9a81620a42c 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 2.2.1.Final 3.5.3.Final 1.1 - 0.21.0 + 0.22.0 1.2 2.7 1.0.7 From 5edea410013411bed24b75164bd302e9d9fa429e Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Fri, 5 Jul 2024 12:52:15 +0200 Subject: [PATCH 2/2] handle review comments Signed-off-by: Ludovic Orban --- .../quic/quiche/foreign/ForeignQuicheConnection.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java index 6d5cd735a93c..b71ee494c3d7 100644 --- a/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java +++ b/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-foreign/src/main/java/org/eclipse/jetty/quic/quiche/foreign/ForeignQuicheConnection.java @@ -855,17 +855,16 @@ public int feedClearBytesForStream(long streamId, ByteBuffer buffer, boolean las long written; try (Arena scope = Arena.ofConfined()) { + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); if (buffer.isDirect()) { // If the ByteBuffer is direct, it can be used without any copy. MemorySegment bufferSegment = MemorySegment.ofBuffer(buffer); - MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, bufferSegment, buffer.remaining(), last, outErrorCode); } else { // If the ByteBuffer is heap-allocated, it must be copied to native memory. - MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); if (buffer.remaining() == 0) { written = quiche_h.quiche_conn_stream_send(quicheConn, streamId, MemorySegment.NULL, 0, last, outErrorCode); @@ -906,23 +905,19 @@ public int drainClearBytesForStream(long streamId, ByteBuffer buffer) throws IOE long read; try (Arena scope = Arena.ofConfined()) { + MemorySegment fin = scope.allocate(NativeHelper.C_CHAR); + MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); if (buffer.isDirect()) { // If the ByteBuffer is direct, it can be used without any copy. MemorySegment bufferSegment = MemorySegment.ofBuffer(buffer); - MemorySegment fin = scope.allocate(NativeHelper.C_CHAR); - MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin, outErrorCode); } else { // If the ByteBuffer is heap-allocated, native memory must be copied to it. MemorySegment bufferSegment = scope.allocate(buffer.remaining()); - - MemorySegment fin = scope.allocate(NativeHelper.C_CHAR); - MemorySegment outErrorCode = scope.allocate(NativeHelper.C_LONG); read = quiche_h.quiche_conn_stream_recv(quicheConn, streamId, bufferSegment, buffer.remaining(), fin, outErrorCode); - if (read > 0) { int prevPosition = buffer.position();