### Create and Start QUIC Server Connector in Java Source: https://github.com/ptrd/kwik/blob/master/readme.md This Java code demonstrates how to build and start a Kwik QUIC server connector. It involves configuring the server with a port, certificate, and connection settings, registering a custom application protocol handler, and then starting the server to listen for incoming connections. ```Java import tech.kwik.core.server.ServerConnector; import tech.kwik.core.server.ServerConnectionConfig; import java.security.KeyStore; import java.util.logging.Logger; // Assume keyStore, serverConnectionConfig, and log are initialized // KeyStore keyStore = ...; // ServerConnectionConfig serverConnectionConfig = ...; // Logger log = Logger.getLogger(MyServer.class.getName()); // Create ServerConnector using builder pattern ServerConnector serverConnector = ServerConnector.builder() .withPort(443) .withKeyStore(keyStore, "servercert", "secret".toCharArray()) .withConfiguration(serverConnectionConfig) .withLogger(log) .build(); // Register the application protocol handler serverConnector.registerApplicationProtocol("myapplicationprotocol", new MyApplicationProtocolConnectionFactory()); // Start the server connector try { serverConnector.start(); log.info("QUIC server started on port 443"); } catch (IOException e) { log.severe("Failed to start QUIC server: " + e.getMessage()); } ``` -------------------------------- ### Initialize and Start a QUIC Server Source: https://context7.com/ptrd/kwik/llms.txt This snippet demonstrates the configuration of connection limits, logging, and TLS security using the ServerConnector builder. It shows both deprecated file-based certificate loading and the recommended Java KeyStore approach. ```java import tech.kwik.core.QuicConnection; import tech.kwik.core.log.Logger; import tech.kwik.core.log.SysOutLogger; import tech.kwik.core.server.ServerConnectionConfig; import tech.kwik.core.server.ServerConnector; import java.io.FileInputStream; import java.security.KeyStore; import java.util.List; public class ServerSetupExample { public static void main(String[] args) throws Exception { Logger log = new SysOutLogger(); ServerConnectionConfig config = ServerConnectionConfig.builder() .maxIdleTimeoutInSeconds(30) .maxConnectionBufferSize(10_000_000) .retryRequired(true) .build(); KeyStore keyStore = KeyStore.getInstance(new java.io.File("cert.jks"), "keystorepassword".toCharArray()); ServerConnector server = ServerConnector.builder() .withPort(4433) .withKeyStore(keyStore, "servercert", "keypassword".toCharArray()) .withSupportedVersions(List.of(QuicConnection.QuicVersion.V1)) .withConfiguration(config) .withLogger(log) .build(); server.start(); } } ``` -------------------------------- ### Implement Echo Server with ApplicationProtocolConnectionFactory Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates how to create a custom application protocol factory and connection handler in Java. The example includes configuring stream limits, buffer sizes, and handling peer-initiated streams asynchronously. ```java import tech.kwik.core.QuicConnection; import tech.kwik.core.QuicStream; import tech.kwik.core.log.Logger; import tech.kwik.core.log.SysOutLogger; import tech.kwik.core.server.*; import java.io.FileInputStream; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class EchoServerExample { public static void main(String[] args) throws Exception { Logger log = new SysOutLogger(); ServerConnectionConfig config = ServerConnectionConfig.builder() .maxOpenPeerInitiatedBidirectionalStreams(50) .build(); ServerConnector server = ServerConnector.builder() .withPort(4433) .withCertificate(new FileInputStream("cert.pem"), new FileInputStream("key.pem")) .withConfiguration(config) .withLogger(log) .build(); server.registerApplicationProtocol("echo", new EchoProtocolFactory(log)); server.start(); } static class EchoProtocolFactory implements ApplicationProtocolConnectionFactory { private final Logger log; private final ExecutorService executor = Executors.newCachedThreadPool(); public EchoProtocolFactory(Logger log) { this.log = log; } @Override public ApplicationProtocolConnection createConnection(String protocol, QuicConnection quicConnection) { return new EchoProtocolConnection(quicConnection, log, executor); } @Override public int maxConcurrentPeerInitiatedBidirectionalStreams() { return Integer.MAX_VALUE; } @Override public int maxConcurrentPeerInitiatedUnidirectionalStreams() { return 0; } @Override public int minBidirectionalStreamReceiverBufferSize() { return 16 * 1024; } @Override public long maxBidirectionalStreamReceiverBufferSize() { return 1024 * 1024; } } static class EchoProtocolConnection implements ApplicationProtocolConnection { private final QuicConnection quicConnection; private final Logger log; private final ExecutorService executor; public EchoProtocolConnection(QuicConnection quicConnection, Logger log, ExecutorService executor) { this.quicConnection = quicConnection; this.log = log; this.executor = executor; } @Override public void acceptPeerInitiatedStream(QuicStream stream) { executor.submit(() -> handleStream(stream)); } private void handleStream(QuicStream stream) { try { byte[] buffer = new byte[64 * 1024]; int totalRead = stream.getInputStream().read(buffer); stream.getOutputStream().write(buffer, 0, totalRead); stream.getOutputStream().close(); } catch (IOException e) { stream.resetStream(0x01); } } } } ``` -------------------------------- ### QUIC Client Connection Source: https://github.com/ptrd/kwik/blob/master/readme.md Example of establishing a QUIC client connection and creating a stream. ```APIDOC ## QUIC Client Connection To connect to a QUIC server, first create a connection object with the builder, e.g.: ```java String applicationProtocolId = "...."; QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://sample.com:443")) .applicationProtocol(applicationProtocolId) .build(); connection.connect(); ``` You need to provide the ALPN protocol ID of the application protocol that you want to run on top of QUIC (and that the server you connect to supports). On the connection object simply call `connect()`: Once connected, you can create a stream and start sending/receiving data, e.g.: ```java QuicStream quicStream = connection.createStream(true); OutputStream output = quicStream.getOutputStream(); output.write(...) output.close(); InputStream input = quicStream.getInputStream(); input.read(...) ``` As QUIC servers generally limit the number of streams that clients can open concurrently, it is wise to close streams when not used anymore. Kwik does this automatically when you `close()` the `OutputStream` and read *all* data from the `InputStream`. If, for some reason, you do not read all data from the `InputStream`, call `QuicStream.abortReading()` to free resources and let the server you know you abandoned the stream. When, for example with local development, the server uses self-signed certificates, you need to disable certificate checking. The builder has a method for this: ```java builder.noServerCertificateCheck() ``` The builder has a lot more methods for configuring the connection, most of which are self-explanatory; see the [Builder interface in QuicClientConnection](https://github.com/ptrd/kwik/blob/master/core/src/main/java/tech/kwik/core/QuicClientConnection.java#L77). The builder method `logger()` requires an implementation of the [Logger interface](https://github.com/ptrd/kwik/blob/master/core/src/main/java/tech/kwik/core/log/Logger.java); Kwik provides two convenient implementations that you can use: `SysOutLogger` and `FileLogger`. Various log categories can be enabled or disabled by the `logXXX()` methods, e.g. `logger.logInfo(true)`. Take a look at the samples in the [sample package](https://github.com/ptrd/kwik/tree/master/samples/src/main/java/tech/kwik/sample) for more inspiration. ``` -------------------------------- ### Datagram Extension Client Example Source: https://context7.com/ptrd/kwik/llms.txt Example demonstrating how a QUIC client can enable and use the Datagram Extension to send and receive unreliable datagrams. ```APIDOC ## Client Example: Datagram Extension Usage ### Description This example shows a QUIC client enabling the Datagram Extension, checking for server support, setting a handler for incoming datagrams, and sending multiple datagrams. ### Method N/A (Client-side implementation) ### Endpoint N/A (Client-side implementation) ### Parameters N/A ### Request Example ```java // Client setup and connection QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("siduck-00") // Datagram test protocol .enableDatagramExtension() // Enable datagram support .noServerCertificateCheck() .logger(log) .build(); connection.connect(); // Verify datagram extension is enabled if (!connection.isDatagramExtensionEnabled()) { System.out.println("Server does not support datagrams"); connection.close(); return; } System.out.println("Max datagram size: " + connection.maxDatagramDataSize() + " bytes"); // Set up handler for incoming datagrams CountDownLatch receivedLatch = new CountDownLatch(3); connection.setDatagramHandler(data -> { String message = new String(data, StandardCharsets.UTF_8); System.out.println("Received datagram: " + message); receivedLatch.countDown(); }); // Send datagrams for (int i = 0; i < 3; i++) { String message = "ping-" + i; System.out.println("Sending datagram: " + message); connection.sendDatagram(message.getBytes(StandardCharsets.UTF_8)); Thread.sleep(500); } // Wait for responses receivedLatch.await(); connection.closeAndWait(); ``` ### Response #### Success Response (200) N/A (Datagrams are handled asynchronously) #### Response Example ``` Received datagram: pong-0 Received datagram: pong-1 Received datagram: pong-2 ``` ``` -------------------------------- ### Registering a ConnectionListener for QUIC Lifecycle Events Source: https://context7.com/ptrd/kwik/llms.txt This example demonstrates how to implement and register a ConnectionListener to handle connection establishment and termination events. It includes logic to inspect close reasons, transport errors, and application-specific error codes. ```java import tech.kwik.core.*; import tech.kwik.core.log.SysOutLogger; import java.net.URI; import java.time.Duration; public class ConnectionListenerExample { public static void main(String[] args) throws Exception { SysOutLogger log = new SysOutLogger(); log.logInfo(true); QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("echo") .maxIdleTimeout(Duration.ofSeconds(10)) .noServerCertificateCheck() .logger(log) .build(); connection.setConnectionListener(new ConnectionListener() { @Override public void connected(ConnectionEstablishedEvent event) { System.out.println("Connection established!"); } @Override public void disconnected(ConnectionTerminatedEvent event) { System.out.println("Connection terminated!"); System.out.println(" Reason: " + event.closeReason()); if (event.hasError()) { System.out.println(" Error: " + event.errorDescription()); } switch (event.closeReason()) { case IdleTimeout: System.out.println(" Connection timed out due to inactivity"); break; case ImmediateClose: System.out.println(" Connection was explicitly closed"); break; case StatelessReset: System.out.println(" Server sent stateless reset"); break; case ConnectionLost: System.out.println(" Connection lost (no response to probes)"); break; } } }); connection.connect(); connection.close(0x00, "Normal shutdown"); } } ``` -------------------------------- ### QuicClientConnection.connect with 0-RTT Early Data Source: https://context7.com/ptrd/kwik/llms.txt This example demonstrates how to establish a QUIC connection using the QuicClientConnection.connect method, including the use of 0-RTT early data by providing a session ticket and preparing data for transmission before the TLS handshake completes. ```APIDOC ## QuicClientConnection.connect(List) ### Description Establishes a connection with optional 0-RTT early data, enabling data transmission before the TLS handshake completes. This requires a previously obtained session ticket and returns the streams created for early data. ### Method POST ### Endpoint /ptrd/kwik ### Parameters #### Request Body - **sessionTicket** (bytes) - Optional - A previously obtained session ticket for enabling 0-RTT. - **earlyData** (List) - Optional - A list of streams containing data to be sent as early data. - **data** (bytes) - Required - The data payload for the stream. - **closeOutput** (boolean) - Required - Indicates if the output stream should be closed after writing data. ### Request Example ```json { "sessionTicket": "base64EncodedTicketData", "earlyData": [ { "data": "SGVsbG8gd2l0aCAwLVJUVCE=", "closeOutput": true } ] } ``` ### Response #### Success Response (200) - **earlyStreams** (List) - A list of streams that were created and used for sending early data. #### Response Example ```json { "earlyStreams": [ { "streamId": 1, "data": "Server response data" } ] } ``` ``` -------------------------------- ### Datagram Extension Server Configuration Source: https://context7.com/ptrd/kwik/llms.txt Example illustrating how a QUIC server can be configured to support and handle the Datagram Extension. ```APIDOC ## Server Configuration: Datagram Extension Support ### Description This example shows how to create a server-side protocol factory that enables the Datagram Extension and handles incoming datagrams, sending back responses. ### Method N/A (Server-side implementation) ### Endpoint N/A (Server-side implementation) ### Parameters N/A ### Request Example ```java // Server protocol factory with datagram support static class DatagramProtocolFactory implements ApplicationProtocolConnectionFactory { @Override public boolean enableDatagramExtension() { return true; // Required for datagram support } @Override public ApplicationProtocolConnection createConnection(String protocol, QuicConnection quicConnection) { if (!quicConnection.isDatagramExtensionEnabled()) { // Client didn't enable datagrams - close connection quicConnection.close(QuicConstants.TransportErrorCode.APPLICATION_ERROR, "Datagram extension required"); return null; } return new DatagramProtocolConnection(quicConnection); } @Override public int maxConcurrentPeerInitiatedBidirectionalStreams() { return 0; // Protocol only uses datagrams } @Override public int maxConcurrentPeerInitiatedUnidirectionalStreams() { return 0; } } static class DatagramProtocolConnection implements ApplicationProtocolConnection { private final QuicConnection connection; public DatagramProtocolConnection(QuicConnection connection) { this.connection = connection; // Set up datagram handler connection.setDatagramHandler(this::handleDatagram); } private void handleDatagram(byte[] data) { String received = new String(data, StandardCharsets.UTF_8); System.out.println("Server received: " + received); // Send response datagram String response = "pong-" + received; connection.sendDatagram(response.getBytes(StandardCharsets.UTF_8)); } } ``` ### Response #### Success Response (200) N/A (Datagrams are handled asynchronously) #### Response Example ``` Server received: ping-0 Server received: ping-1 Server received: ping-2 ``` ``` -------------------------------- ### Configure Connection Builder Source: https://github.com/ptrd/kwik/blob/master/readme.md Example of configuring the connection builder to disable server certificate checks for local development. ```java builder.noServerCertificateCheck(); ``` -------------------------------- ### Create QUIC Streams with QuicConnection.createStream (Java) Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates creating bidirectional and unidirectional QUIC streams using QuicConnection.createStream. It shows how to send and receive data on bidirectional streams and send data on unidirectional streams. The example also illustrates handling multiple concurrent streams. ```Java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.QuicStream; import tech.kwik.core.log.SysOutLogger; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.nio.charset.StandardCharsets; public class StreamExample { public static void main(String[] args) throws Exception { SysOutLogger log = new SysOutLogger(); log.logStream(true); QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("echo") .noServerCertificateCheck() .logger(log) .build(); connection.connect(); // Create a bidirectional stream (request-response pattern) QuicStream bidirectionalStream = connection.createStream(true); System.out.println("Stream ID: " + bidirectionalStream.getStreamId()); System.out.println("Is bidirectional: " + bidirectionalStream.isBidirectional()); OutputStream output = bidirectionalStream.getOutputStream(); output.write("Request data".getBytes(StandardCharsets.UTF_8)); output.close(); // Signal end of data to peer InputStream input = bidirectionalStream.getInputStream(); byte[] response = input.readAllBytes(); System.out.println("Response: " + new String(response, StandardCharsets.UTF_8)); // Create a unidirectional stream (send-only) QuicStream unidirectionalStream = connection.createStream(false); System.out.println("Unidirectional stream ID: " + unidirectionalStream.getStreamId()); System.out.println("Is unidirectional: " + unidirectionalStream.isUnidirectional()); unidirectionalStream.getOutputStream().write("One-way data".getBytes(StandardCharsets.UTF_8)); unidirectionalStream.getOutputStream().close(); // Multiple concurrent streams for (int i = 0; i < 5; i++) { QuicStream stream = connection.createStream(true); final int streamNum = i; new Thread(() -> { try { stream.getOutputStream().write(("Request " + streamNum).getBytes()); stream.getOutputStream().close(); System.out.println("Stream " + streamNum + " response: " + new String(stream.getInputStream().readAllBytes())); } catch (Exception e) { e.printStackTrace(); } }).start(); } Thread.sleep(2000); connection.closeAndWait(); } } ``` -------------------------------- ### Java: Abort and Reset QUIC Streams Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates terminating QUIC stream operations using abortReading() to stop receiving data and resetStream() to abruptly close the sending side. Both methods accept application-specific error codes. This example shows how to use these methods in response to receiving sufficient data or encountering an error condition. ```java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.QuicStream; import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; public class StreamAbortExample { public static void main(String[] args) throws Exception { QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("test-protocol") .noServerCertificateCheck() .build(); connection.connect(); // Example 1: Abort reading when we've received enough data QuicStream stream1 = connection.createStream(true); stream1.getOutputStream().write("GET /large-file".getBytes(StandardCharsets.UTF_8)); stream1.getOutputStream().close(); InputStream input = stream1.getInputStream(); byte[] buffer = new byte[1024]; int totalRead = 0; int maxBytes = 4096; // Only want first 4KB while (totalRead < maxBytes) { int read = input.read(buffer); if (read == -1) break; totalRead += read; System.out.println("Read " + totalRead + " bytes"); } // Tell peer to stop sending - we have enough data // Error code 0 typically means no error, just cancellation stream1.abortReading(0); System.out.println("Aborted reading after " + totalRead + " bytes"); // Example 2: Reset stream on error condition QuicStream stream2 = connection.createStream(true); try { stream2.getOutputStream().write("Invalid request".getBytes()); // Simulate detecting an error condition boolean errorDetected = true; if (errorDetected) { // Reset the stream with application-specific error code stream2.resetStream(0x100); // Application-defined error code System.out.println("Stream reset due to error"); } } catch (Exception e) { stream2.resetStream(0x101); // Different error code for exceptions } connection.closeAndWait(); } } ``` -------------------------------- ### Initialize and Connect a QUIC Client Source: https://github.com/ptrd/kwik/blob/master/readme.md Demonstrates how to build a connection to a QUIC server and initiate the connection process. ```java String applicationProtocolId = "...."; QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://sample.com:443")) .applicationProtocol(applicationProtocolId) .build(); connection.connect(); ``` -------------------------------- ### Run Kwik Sample Client (Shell) Source: https://github.com/ptrd/kwik/blob/master/readme.md Demonstrates how to run the Kwik command-line client for experimenting with the QUIC protocol. It includes instructions for using the `kwik.sh` script, unzipping the distribution, and running the client with specific arguments, including options for HTTP/3 support. ```bash # Using the script: ./kwik.sh # Unzipping distribution: unzip cli/build/distributions/kwik-cli-*.zip ./kwik-cli # or on Windows: kwik-cli.bat # Running with gradle (from cli directory): gradle run --args='-T -H /index.html example.com 4433' ``` -------------------------------- ### Establish QUIC Client Connection and Transfer Data (Java) Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates how to build and establish a QUIC client connection using Kwik. It covers configuring the connection with a URI, ALPN, timeouts, and stream limits, then proceeds to create a bidirectional stream, send an HTTP request, and read the response. Dependencies include Kwik core library and standard Java networking classes. ```Java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.QuicConnection; import tech.kwik.core.QuicStream; import tech.kwik.core.log.SysOutLogger; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; public class QuicClientExample { public static void main(String[] args) throws Exception { // Configure logging SysOutLogger log = new SysOutLogger(); log.logInfo(true); log.logPackets(true); // Build and configure the QUIC connection QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://example.com:443")) .applicationProtocol("h3") // ALPN protocol identifier .version(QuicConnection.QuicVersion.V1) // Use QUIC v1 .connectTimeout(Duration.ofSeconds(10)) .maxIdleTimeout(Duration.ofSeconds(30)) .maxOpenPeerInitiatedBidirectionalStreams(100) .maxOpenPeerInitiatedUnidirectionalStreams(10) .logger(log) // .noServerCertificateCheck() // For development only // .customTrustStore(trustStore) // Custom CA certificates // .clientCertificate(cert) // Client authentication // .clientCertificateKey(privateKey) .build(); // Establish the connection connection.connect(); System.out.println("Connected: " + connection.isConnected()); System.out.println("Server address: " + connection.getServerAddress()); System.out.println("QUIC version: " + connection.getQuicVersion()); // Create a bidirectional stream and send data QuicStream stream = connection.createStream(true); OutputStream output = stream.getOutputStream(); output.write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.UTF_8)); output.close(); // Read response InputStream input = stream.getInputStream(); byte[] response = input.readAllBytes(); System.out.println("Response: " + new String(response, StandardCharsets.UTF_8)); // Close connection gracefully connection.closeAndWait(); } } ``` -------------------------------- ### Build Kwik Project with Gradle (Shell) Source: https://github.com/ptrd/kwik/blob/master/readme.md Instructions for building the Kwik project using Gradle wrapper. This process clones the repository, navigates into the directory, and executes the build command. The output artifacts are placed in each submodule's `build/libs` directory. ```bash # Clone the git repository and cd into the directory git clone cd # Build with gradle wrapper ./gradlew build # or on Windows: gradlew.bat build ``` -------------------------------- ### Manage QUIC Streams Source: https://github.com/ptrd/kwik/blob/master/readme.md Shows how to create a stream, write data to the output stream, and read data from the input stream. ```java QuicStream quicStream = connection.createStream(true); OutputStream output = quicStream.getOutputStream(); output.write(...); output.close(); InputStream input = quicStream.getInputStream(); input.read(...); ``` -------------------------------- ### Establish QUIC Connection with 0-RTT Early Data in Java Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates establishing a QUIC connection with optional 0-RTT early data using Java. It shows how to load a session ticket, prepare and send early data, handle the response, and save new session tickets for future connections. This requires the QuicClientConnection class from the tech.kwik library. ```java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.QuicConnection; import tech.kwik.core.QuicSessionTicket; import tech.kwik.core.QuicStream; import tech.kwik.core.log.SysOutLogger; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.List; public class ZeroRttExample { private static final String TICKET_FILE = "session-ticket.bin"; public static void main(String[] args) throws Exception { byte[] requestData = "Hello with 0-RTT!".getBytes(StandardCharsets.UTF_8); SysOutLogger log = new SysOutLogger(); log.logPackets(true); QuicClientConnection.Builder builder = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("echo") .version(QuicConnection.QuicVersion.V1) .noServerCertificateCheck() .logger(log); // Try to load existing session ticket for 0-RTT List earlyData = List.of(); Path ticketPath = Path.of(TICKET_FILE); if (Files.exists(ticketPath)) { byte[] ticketData = Files.readAllBytes(ticketPath); builder.sessionTicket(ticketData); // Prepare early data to send with 0-RTT earlyData = List.of( new QuicClientConnection.StreamEarlyData(requestData, true) // closeOutput=true ); System.out.println("Using 0-RTT with session ticket"); } QuicClientConnection connection = builder.build(); // Connect with early data (returns streams used for 0-RTT) List earlyStreams = connection.connect(earlyData); // Handle response from early data stream or create new stream QuicStream stream = earlyStreams.stream().findFirst().orElseGet(() -> { try { QuicStream s = connection.createStream(true); s.getOutputStream().write(requestData); s.getOutputStream().close(); return s; } catch (Exception e) { throw new RuntimeException(e); } }); // Read response System.out.print("Server response: "); stream.getInputStream().transferTo(System.out); System.out.println(); // Save new session tickets for next connection List tickets = connection.getNewSessionTickets(); if (!tickets.isEmpty()) { Files.write(ticketPath, tickets.get(0).serialize(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); System.out.println("Session ticket saved for future 0-RTT"); } connection.closeAndWait(); } } ``` -------------------------------- ### Retrieve Connection Statistics in Java Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates how to initialize a QuicClientConnection, perform data transfers, and extract performance metrics such as datagrams sent, packet loss, and RTT measurements. ```java import tech.kwik.core.*; import tech.kwik.core.log.SysOutLogger; import java.net.URI; import java.nio.charset.StandardCharsets; public class StatisticsExample { public static void main(String[] args) throws Exception { SysOutLogger log = new SysOutLogger(); log.logStats(true); log.logRecovery(true); QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("echo") .noServerCertificateCheck() .logger(log) .build(); connection.connect(); for (int i = 0; i < 10; i++) { QuicStream stream = connection.createStream(true); byte[] data = ("Request " + i + " with some payload data").getBytes(StandardCharsets.UTF_8); stream.getOutputStream().write(data); stream.getOutputStream().close(); stream.getInputStream().readAllBytes(); } Statistics stats = connection.getStats(); System.out.println("Bytes sent: " + stats.bytesSent()); System.out.println("Smoothed RTT: " + stats.smoothedRtt() + " ms"); connection.closeAndWait(); } } ``` -------------------------------- ### Generate Java KeyStore from PEM Certificate and Key Source: https://github.com/ptrd/kwik/blob/master/readme.md This section provides shell commands to convert PEM-formatted certificate and private key files into a Java KeyStore (.jks) file. This is necessary for the Kwik `ServerConnector` to use the server's credentials for TLS authentication. The process involves creating a PKCS12 file first, then importing it into a JKS keystore. ```Shell # Convert PEM certificate and key to PKCS12 format openssl pkcs12 -export -clcerts -in cert.pem -inkey key.pem -name servercert -out cert.p12 # Import PKCS12 keystore into a Java KeyStore (JKS) keytool -keystore cert.jks -importkeystore \ -srckeystore cert.p12 -srcstoretype PKCS12 \ -deststorepass secret -srcstorepass secret # The resulting cert.jks file can be used with ServerConnector.builder().withKeyStore(...) ``` -------------------------------- ### Build Kwik Library from Source Source: https://context7.com/ptrd/kwik/llms.txt Clone the Kwik repository and build the library using Gradle. This process generates the necessary JAR files for the core library and the command-line interface. ```bash # Build from source git clone https://github.com/ptrd/kwik.git cd kwik ./gradlew build # Output JAR locations: # - core/build/libs/kwik-*.jar # - cli/build/libs/kwik-cli-*.jar ``` -------------------------------- ### Configure Logging Categories in Java Source: https://context7.com/ptrd/kwik/llms.txt Shows how to set up console or file logging, configure specific log categories like congestion control and secrets, and use the logger for custom application messages. ```java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.log.FileLogger; import tech.kwik.core.log.Logger; import tech.kwik.core.log.SysOutLogger; import java.io.File; import java.net.URI; public class LoggerExample { public static void main(String[] args) throws Exception { SysOutLogger consoleLog = new SysOutLogger(); Logger log = consoleLog; log.logPackets(true); log.logRecovery(true); log.logCongestionControl(true); log.logSecrets(true); QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .logger(log) .build(); connection.connect(); log.info("Connection established successfully"); connection.closeAndWait(); } } ``` -------------------------------- ### Implement QUIC Server Protocol Handler in Java Source: https://github.com/ptrd/kwik/blob/master/readme.md This snippet demonstrates the core Java interfaces required for a Kwik QUIC server's application protocol. It involves implementing `ApplicationProtocolConnectionFactory` and `ApplicationProtocolConnection` to define how the server handles incoming streams and connections for a custom protocol. The `ApplicationProtocolSettings` methods specify stream limits. ```Java public class MyApplicationProtocolConnectionFactory implements ApplicationProtocolConnectionFactory { @Override public ApplicationProtocolConnection createConnection(Connection connection) { return new MyApplicationProtocolConnection(); } } public class MyApplicationProtocolConnection implements ApplicationProtocolConnection { @Override public void acceptPeerInitiatedStream(Stream stream) { // Handle new stream initiation, e.g., start a new stream handler thread new Thread(() -> handleStream(stream)).start(); } private void handleStream(Stream stream) { // Implement request-response logic: read request, process, write response, close stream try { // Example: Read from stream byte[] requestData = new byte[1024]; int bytesRead = stream.read(requestData); // Process requestData... // Example: Write to stream byte[] responseData = "Processed Response".getBytes(); stream.write(responseData); } catch (IOException e) { // Handle exceptions } finally { try { stream.close(); } catch (IOException e) { // Handle exceptions } } } // Implement other methods as needed, e.g., acceptLocalInitiatedStream } public class MyApplicationProtocolSettings implements ApplicationProtocolSettings { @Override public int maxConcurrentPeerInitiatedUnidirectionalStreams() { return 0; // Or Long.MAX_VALUE, or a specific number } @Override public int maxConcurrentPeerInitiatedBidirectionalStreams() { return Long.MAX_VALUE; // Or 0, or a specific number } } ``` -------------------------------- ### Java Module System Integration Source: https://context7.com/ptrd/kwik/llms.txt How to configure your module-info.java to include Kwik modules. ```APIDOC ## Java Module System Configuration ### Description Configure the Java Module System to require Kwik core modules. ### Module Configuration ```java module myapp { requires tech.kwik.core; // requires tech.kwik.h09; // requires tech.kwik.qlog; } ``` ``` -------------------------------- ### Maven Dependency Configuration Source: https://context7.com/ptrd/kwik/llms.txt Instructions for adding the Kwik core library and optional HTTP/3 support to your Maven project. ```APIDOC ## Maven Dependency Configuration ### Description Add the Kwik library to your project's pom.xml to enable QUIC networking capabilities. ### Dependency Configuration ```xml tech.kwik kwik 0.10.8 tech.kwik flupke 0.4.0 ``` ``` -------------------------------- ### Configure Java Module System for Kwik Source: https://context7.com/ptrd/kwik/llms.txt Specify Kwik's core module requirement in your module-info.java file. Additional requires statements can be uncommented for other Kwik modules like HTTP/0.9, QLOG, or sample utilities. ```java // module-info.java for Java Module System module myapp { requires tech.kwik.core; // requires tech.kwik.h09; // For HTTP/0.9 // requires tech.kwik.qlog; // For QLOG support // requires tech.kwik.samples; // For sample utilities } ``` -------------------------------- ### QUIC Datagram Client and Server Implementation in Java Source: https://context7.com/ptrd/kwik/llms.txt This Java code demonstrates how to enable and use the Datagram Extension (RFC 9221) for unreliable datagram transmission over QUIC connections. It includes client-side logic for connecting, sending, and receiving datagrams, as well as server-side components for handling incoming datagrams and sending responses. Both client and server must explicitly enable the extension for it to function. ```java import tech.kwik.core.QuicClientConnection; import tech.kwik.core.QuicConnection; import tech.kwik.core.QuicConstants; import tech.kwik.core.log.SysOutLogger; import tech.kwik.core.server.*; import java.io.FileInputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; public class DatagramExample { // Client example public static void clientExample() throws Exception { SysOutLogger log = new SysOutLogger(); log.logInfo(true); QuicClientConnection connection = QuicClientConnection.newBuilder() .uri(URI.create("https://localhost:4433")) .applicationProtocol("siduck-00") // Datagram test protocol .enableDatagramExtension() // Enable datagram support .noServerCertificateCheck() .logger(log) .build(); connection.connect(); // Verify datagram extension is enabled if (!connection.isDatagramExtensionEnabled()) { System.out.println("Server does not support datagrams"); connection.close(); return; } System.out.println("Max datagram size: " + connection.maxDatagramDataSize() + " bytes"); // Set up handler for incoming datagrams CountDownLatch receivedLatch = new CountDownLatch(3); connection.setDatagramHandler(data -> { String message = new String(data, StandardCharsets.UTF_8); System.out.println("Received datagram: " + message); receivedLatch.countDown(); }); // Send datagrams for (int i = 0; i < 3; i++) { String message = "ping-" + i; System.out.println("Sending datagram: " + message); connection.sendDatagram(message.getBytes(StandardCharsets.UTF_8)); Thread.sleep(500); } // Wait for responses receivedLatch.await(); connection.closeAndWait(); } // Server protocol factory with datagram support static class DatagramProtocolFactory implements ApplicationProtocolConnectionFactory { @Override public boolean enableDatagramExtension() { return true; // Required for datagram support } @Override public ApplicationProtocolConnection createConnection(String protocol, QuicConnection quicConnection) { if (!quicConnection.isDatagramExtensionEnabled()) { // Client didn't enable datagrams - close connection quicConnection.close(QuicConstants.TransportErrorCode.APPLICATION_ERROR, "Datagram extension required"); return null; } return new DatagramProtocolConnection(quicConnection); } @Override public int maxConcurrentPeerInitiatedBidirectionalStreams() { return 0; // Protocol only uses datagrams } @Override public int maxConcurrentPeerInitiatedUnidirectionalStreams() { return 0; } } static class DatagramProtocolConnection implements ApplicationProtocolConnection { private final QuicConnection connection; public DatagramProtocolConnection(QuicConnection connection) { this.connection = connection; // Set up datagram handler connection.setDatagramHandler(this::handleDatagram); } private void handleDatagram(byte[] data) { String received = new String(data, StandardCharsets.UTF_8); System.out.println("Server received: " + received); // Send response datagram String response = "pong-" + received; connection.sendDatagram(response.getBytes(StandardCharsets.UTF_8)); } } public static void main(String[] args) throws Exception { clientExample(); } } ``` -------------------------------- ### Configure Server Connection in Kwik (Java) Source: https://github.com/ptrd/kwik/blob/master/readme.md Configures a server connection for Kwik by setting the maximum number of open bidirectional streams. This is a mandatory setting to maximize concurrent streams on a connection. The default for unidirectional streams is 0, and it's recommended not to set it. ```java ServerConnectionConfig.builder() .maxOpenPeerInitiatedBidirectionalStreams(50) // Mandatory setting to maximize concurrent streams on a connection. .build(); ``` -------------------------------- ### QuicConnection.createStream Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates creating bidirectional and unidirectional QUIC streams, sending data, and receiving responses. ```APIDOC ## QuicConnection.createStream(boolean bidirectional) ### Description Creates a new QUIC stream for data transmission. Bidirectional streams allow both sending and receiving data, while unidirectional streams only allow sending. The method blocks if stream credits are exhausted until credits become available. ### Method `createStream(boolean bidirectional)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```java // Example usage within a larger context QuicClientConnection connection = ...; QuicStream bidirectionalStream = connection.createStream(true); OutputStream output = bidirectionalStream.getOutputStream(); output.write("Request data".getBytes(StandardCharsets.UTF_8)); output.close(); InputStream input = bidirectionalStream.getInputStream(); byte[] response = input.readAllBytes(); QuicStream unidirectionalStream = connection.createStream(false); unidirectionalStream.getOutputStream().write("One-way data".getBytes(StandardCharsets.UTF_8)); unidirectionalStream.getOutputStream().close(); ``` ### Response #### Success Response (200) Returns a `QuicStream` object representing the newly created stream. #### Response Example ```java // Conceptual representation of the QuicStream object { "streamId": 123, "isBidirectional": true } ``` ### Error Handling - **Stream Credit Exhaustion**: The method may block if stream credits are exhausted. Consider implementing timeouts or backoff strategies if this becomes an issue. - **Connection Errors**: Standard QUIC connection errors may occur during stream creation. ``` -------------------------------- ### Java Module System Source: https://github.com/ptrd/kwik/blob/master/readme.md Information on Kwik artifacts and their corresponding Java module names. ```APIDOC ## Java Module System The following Kwik artifacts define a Java module with the given name: - kwik: `tech.kwik.core` - kwik-h09: `tech.kwik.h09` - kwik-qlog: `tech.kwik.qlog` - kwik-samples: `tech.kwik.samples` ``` -------------------------------- ### QuicStream.abortReading and QuicStream.resetStream Source: https://context7.com/ptrd/kwik/llms.txt Demonstrates how to use abortReading to stop receiving data and resetStream to abruptly terminate the sending side of a stream, both with application-specific error codes. ```APIDOC ## QuicStream.abortReading(long errorCode) / QuicStream.resetStream(long errorCode) ### Description Terminates stream operations. `abortReading()` sends a STOP_SENDING frame to tell the peer to stop sending data. `resetStream()` abruptly terminates the sending side with a RESET_STREAM frame. Both accept an application-protocol-specific error code. ### Method `abortReading(long errorCode)`: Sends a STOP_SENDING frame. `resetStream(long errorCode)`: Sends a RESET_STREAM frame. ### Endpoint N/A (These are methods on a QuicStream object) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```java // Example 1: Abort reading stream1.abortReading(0); // Example 2: Reset stream on error stream2.resetStream(0x100); ``` ### Response #### Success Response (200) N/A (These methods do not return a value, but indicate stream termination) #### Response Example N/A ``` -------------------------------- ### Add Kwik Dependency to Maven Project Source: https://context7.com/ptrd/kwik/llms.txt Configure your pom.xml to include the Kwik core library and optional Flupke (HTTP/3) support. This allows your Java application to utilize QUIC protocol features. ```xml tech.kwik kwik 0.10.8 tech.kwik flupke 0.4.0 ```