diff --git a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnection.java b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnection.java index 730617f111f..0fa88f82345 100644 --- a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnection.java +++ b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnection.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.quic.quiche; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -101,11 +102,15 @@ public class QuicheConnection String[] applicationProtos = config.getApplicationProtos(); if (applicationProtos != null) { - StringBuilder sb = new StringBuilder(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (String proto : applicationProtos) - sb.append((char)proto.getBytes(LibQuiche.CHARSET).length).append(proto); - String theProtos = sb.toString(); - LibQuiche.INSTANCE.quiche_config_set_application_protos(quicheConfig, theProtos, new size_t(theProtos.getBytes(LibQuiche.CHARSET).length)); + { + byte[] bytes = proto.getBytes(LibQuiche.CHARSET); + baos.write(bytes.length); + baos.write(bytes); + } + byte[] bytes = baos.toByteArray(); + LibQuiche.INSTANCE.quiche_config_set_application_protos(quicheConfig, bytes, new size_t(bytes.length)); } QuicheConfig.CongestionControl cc = config.getCongestionControl(); @@ -222,7 +227,7 @@ public class 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 : " + generated); + throw new IOException("failed to create vneg packet : " + LibQuiche.quiche_error.errToString(generated.intValue())); return true; } diff --git a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnectionId.java b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnectionId.java index b67e0bb5103..df09c92d210 100644 --- a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnectionId.java +++ b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/QuicheConnectionId.java @@ -47,27 +47,15 @@ public class QuicheConnectionId private static String bytesToHex(byte[] bytes) { byte[] hexChars = new byte[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) + for (int i = 0; i < bytes.length; i++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + int c = bytes[i] & 0xFF; + hexChars[i * 2] = HEX_ARRAY[c >>> 4]; + hexChars[i * 2 + 1] = HEX_ARRAY[c & 0x0F]; } return new String(hexChars, StandardCharsets.US_ASCII); } - public static QuicheConnectionId fromCid(byte[] cid) - { - byte[] sizedDcid = resizeIfNeeded(cid, cid.length); - return new QuicheConnectionId(sizedDcid); - } - - static QuicheConnectionId fromCid(byte[] dcid, size_t_pointer dcidLen) - { - byte[] sizedDcid = resizeIfNeeded(dcid, (int)dcidLen.getValue()); - return new QuicheConnectionId(sizedDcid); - } - /** * Does not consume the packet byte buffer. */ @@ -94,7 +82,8 @@ public class QuicheConnectionId token, tokenLen); if (rc < 0) return null; - return fromCid(dcid, dcidLen); + byte[] sizedDcid = resizeIfNeeded(dcid, (int)dcidLen.getValue()); + return new QuicheConnectionId(sizedDcid); } private static byte[] resizeIfNeeded(byte[] buffer, int length) diff --git a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/ffi/LibQuiche.java b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/ffi/LibQuiche.java index 025d09ee694..e907362c294 100644 --- a/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/ffi/LibQuiche.java +++ b/jetty-quic/quic-quiche/src/main/java/org/eclipse/jetty/quic/quiche/ffi/LibQuiche.java @@ -33,8 +33,10 @@ public interface LibQuiche extends Library // It needs to be reviewed each time the native lib version changes. String EXPECTED_QUICHE_VERSION = "0.10.0"; - // load the native lib + // The charset used to convert java.lang.String to char * and vice versa. Charset CHARSET = StandardCharsets.UTF_8; + + // Load the native lib. LibQuiche INSTANCE = Native.load("quiche", LibQuiche.class, Map.of(Library.OPTION_STRING_ENCODING, CHARSET.name())); class Logging @@ -189,7 +191,7 @@ public interface LibQuiche extends Library void quiche_config_verify_peer(quiche_config config, boolean v); // Configures the list of supported application protocols. - int quiche_config_set_application_protos(quiche_config config, String protos, size_t protos_len); + int quiche_config_set_application_protos(quiche_config config, byte[] protos, size_t protos_len); // Sets the `max_idle_timeout` transport parameter. void quiche_config_set_max_idle_timeout(quiche_config config, uint64_t v); @@ -437,7 +439,7 @@ public interface LibQuiche extends Library boolean quiche_conn_peer_error(quiche_conn conn, bool_pointer is_app, uint64_t_pointer error_code, - char_pointer/*const uint8_t ***/ reason, + char_pointer reason, size_t_pointer reason_len); // Returns true if a connection error was queued or sent, and updates the provided @@ -445,7 +447,7 @@ public interface LibQuiche extends Library boolean quiche_conn_local_error(quiche_conn conn, bool_pointer is_app, uint64_t_pointer error_code, - Pointer/*const uint8_t ***/ reason, + char_pointer reason, size_t_pointer reason_len); // Closes the connection with the given error and reason. diff --git a/jetty-quic/quic-quiche/src/test/java/org/eclipse/jetty/quic/quiche/LowLevelQuicheTest.java b/jetty-quic/quic-quiche/src/test/java/org/eclipse/jetty/quic/quiche/LowLevelQuicheTest.java index 49b4f93f0c1..1e59a6b61b2 100644 --- a/jetty-quic/quic-quiche/src/test/java/org/eclipse/jetty/quic/quiche/LowLevelQuicheTest.java +++ b/jetty-quic/quic-quiche/src/test/java/org/eclipse/jetty/quic/quiche/LowLevelQuicheTest.java @@ -249,10 +249,9 @@ public class LowLevelQuicheTest AbstractMap.SimpleImmutableEntry entry = new AbstractMap.SimpleImmutableEntry<>(clientQuicheConnection, serverQuicheConnection); - StringBuilder sb = new StringBuilder(); + int protosLen = 0; for (String proto : clientQuicheConfig.getApplicationProtos()) - sb.append((char)proto.getBytes(LibQuiche.CHARSET).length).append(proto); - int protosLen = sb.toString().getBytes(LibQuiche.CHARSET).length; + protosLen += 1 + proto.getBytes(LibQuiche.CHARSET).length; drainServerToFeedClient(entry, 300 + protosLen); assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));