Class QuicClient

java.lang.Object
io.github.mahmoudimus.quic.QuicClient
All Implemented Interfaces:
AutoCloseable

public final class QuicClient extends Object implements AutoCloseable
A QUIC client endpoint on one UDP socket, from which any number of connections can be made.

 ClientConfig config = ClientConfig.builder(TlsConfig.builder()
         .serverName("example.com")
         .alpnProtocols("echo")
         .build()).build();
 try (QuicClient client = QuicClient.create(config);
         QuicConnection connection = client.connect(new InetSocketAddress("example.com", 4433))) {
     QuicStream stream = connection.openBidirectionalStream();
     try (OutputStream out = stream.getOutputStream()) {
         out.write(request);
     }
     byte[] response = stream.getInputStream().readAllBytes();
 }
 

Resumption and 0-RTT. Connections keep the session tickets and NEW_TOKEN tokens servers send in a SessionCache: the one configured, or else one of the client's own, which sessionCache() returns. The next connection to the same server resumes the session and skips the server's Retry. With earlyData on, connectEarly(java.net.InetSocketAddress, java.lang.String, java.time.Duration) returns at once when it can send 0-RTT data:


 QuicConnection connection = client.connectEarly(address, null, null);
 QuicStream stream = connection.openBidirectionalStream();   // usable at once
 stream.getOutputStream().write(idempotentRequest);          // sent as 0-RTT data
 connection.awaitHandshake(null);
 boolean accepted = connection.earlyDataAccepted();          // if not, it was sent again in 1-RTT
 

Send only what is safe to replay as 0-RTT data: an attacker can capture and resend it.

Closing the client closes its connections and stops its threads.

  • Method Details

    • sessionCache

      public SessionCache sessionCache()
      The cache of session tickets and tokens connections use by default.
      Returns:
      the cache
    • create

      public static QuicClient create(ClientConfig config) throws IOException
      A client on an ephemeral IPv4 port, with the default endpoint settings.
      Parameters:
      config - how to connect
      Returns:
      the client
      Throws:
      IOException - if the socket cannot be bound
    • create

      public static QuicClient create(ClientConfig config, InetSocketAddress bindAddress, EndpointConfig endpointConfig) throws IOException
      A client.
      Parameters:
      config - how to connect
      bindAddress - the local address; use an IPv6 address to reach IPv6 servers
      endpointConfig - the endpoint settings: connection IDs, reset key, versions
      Returns:
      the client
      Throws:
      IOException - if the socket cannot be bound
    • connect

      public QuicConnection connect(InetSocketAddress remote) throws IOException
      Connects with the TLS configuration's server name, waiting for the handshake.
      Parameters:
      remote - the server's address
      Returns:
      the established connection
      Throws:
      QuicConnectionException - if the handshake fails or times out (the idle timeout)
      IOException - if the client is closed
    • connect

      public QuicConnection connect(InetSocketAddress remote, String serverName, Duration timeout) throws IOException
      Connects, waiting for the handshake.
      Parameters:
      remote - the server's address
      serverName - the name to send as SNI and check the certificate against, or null for the TLS configuration's
      timeout - the longest to wait for the handshake, or null for the idle timeout
      Returns:
      the established connection
      Throws:
      QuicConnectionException - if the handshake fails or times out
      IOException - if the client is closed
    • connect

      public QuicConnection connect(InetSocketAddress remote, String serverName, Duration timeout, SessionCache cache) throws IOException
      Connects with a cache of session tickets and tokens, waiting for the handshake.
      Parameters:
      remote - the server's address
      serverName - the name to send as SNI and check the certificate against, or null for the TLS configuration's
      timeout - the longest to wait for the handshake, or null for the idle timeout
      cache - the tickets and tokens to resume with and keep, or SessionCache.none()
      Returns:
      the established connection
      Throws:
      QuicConnectionException - if the handshake fails or times out
      IOException - if the client is closed
    • connectEarly

      public QuicConnection connectEarly(InetSocketAddress remote, String serverName, Duration timeout) throws IOException
      Connects, returning at once if the connection can send 0-RTT data (it resumes with a ticket that allows it, and the TLS configuration enables early data); otherwise waiting for the handshake as connect(InetSocketAddress, String, Duration) does. Streams of a 0-RTT connection can be used at once, within the limits the server set in the earlier session; QuicConnection.awaitHandshake(java.time.Duration) waits for the handshake, and QuicConnection.earlyDataAccepted() tells whether the server took the early data. If it did not, the data is sent again in 1-RTT packets.
      Parameters:
      remote - the server's address
      serverName - the name for SNI and the certificate, or null for the TLS configuration's
      timeout - the longest to wait for a handshake without 0-RTT, or null for the idle timeout
      Returns:
      the connection, possibly still handshaking
      Throws:
      QuicConnectionException - if a handshake without 0-RTT fails or times out
      IOException - if the client is closed
    • connectEarly

      public QuicConnection connectEarly(InetSocketAddress remote, String serverName, Duration timeout, SessionCache cache) throws IOException
      Connects with a cache of session tickets and tokens, returning at once if the connection can send 0-RTT data.
      Parameters:
      remote - the server's address
      serverName - the name for SNI and the certificate, or null for the TLS configuration's
      timeout - the longest to wait for a handshake without 0-RTT, or null for the idle timeout
      cache - the tickets and tokens to resume with and keep
      Returns:
      the connection, possibly still handshaking
      Throws:
      QuicConnectionException - if a handshake without 0-RTT fails or times out
      IOException - if the client is closed
      See Also:
    • localAddress

      public InetSocketAddress localAddress()
      The address the client is bound to.
      Returns:
      the address, with the actual port
    • connectionCount

      public int connectionCount()
      The number of connections, including those still handshaking or closing.
      Returns:
      the count
    • observe

      public void observe(QuicConnection.Observer observer)
      Sets what learns of this endpoint's connections as they open, complete their handshakes and close, with their statistics; null for nothing. Each connection keeps the observer set when it started, so connections that started before are not observed.
      Parameters:
      observer - the observer, or null
    • endpointStats

      public EndpointStats endpointStats()
      What the endpoint answered itself, without a connection: Version Negotiation, Retry, stateless resets and refusals.
      Returns:
      the counts so far
    • close

      public void close()
      Closes every connection (CONNECTION_CLOSE with code 0), stops the threads and the socket.
      Specified by:
      close in interface AutoCloseable