Class QuicConnection
- All Implemented Interfaces:
AutoCloseable
InputStreams and OutputStreams, send and receive
datagrams. Operations block while flow control, the stream limits or the peer hold them up, and
fail with a QuicConnectionException once the connection is gone.
Connections come from QuicServer.accept() and QuicClient.connect(java.net.InetSocketAddress). Each one is
driven by a virtual thread of its endpoint; any number of threads may use a connection and its
streams at once.
Migration. A server's connection follows a client that moves to a new address (a NAT
rebinding, or a client that migrates), validating the new path first, unless
its configuration forbids migration; remoteAddress() then changes. A client connection
moves with migrate(java.net.InetSocketAddress) (probing the new path first) or rebind(java.net.InetSocketAddress) (at once), and to a
server's preferred address on its own.
0-RTT. A connection from QuicClient.connectEarly(java.net.InetSocketAddress, java.lang.String, java.time.Duration) may still be handshaking: its
streams can be opened and written at once, and what is written goes out as 0-RTT data. A server
that accepted 0-RTT hands the connection out before its handshake completes; data that arrived
as early data (QuicStream.receivedEarlyData()) may have been replayed by an attacker.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceLearns of an endpoint's connections as they open, complete their handshakes and close, for statistics: set withQuicServer.observe(io.github.mahmoudimus.quic.QuicConnection.Observer)orQuicClient.observe(io.github.mahmoudimus.quic.QuicConnection.Observer).static final recordConnection statistics. -
Method Summary
Modifier and TypeMethodDescriptionWaits for a stream the peer opened, bidirectional or unidirectional (receive-only).alpn()The application protocol agreed with ALPN.awaitClosed(Duration timeout) Waits until the connection has ended, for any reason.booleanawaitHandshake(Duration timeout) Waits for the handshake to complete: for a connection fromQuicClient.connectEarly(java.net.InetSocketAddress, java.lang.String, java.time.Duration)or one a server accepted with 0-RTT data.The negotiated cipher suite.voidclose()Closes the connection with code 0 and no reason.voidCloses the connection with an application error code: CONNECTION_CLOSE is sent at once and streams fail.Why the connection ended.booleanWhether the server accepted 0-RTT data: on a client, known once the handshake completes; on a server, from the start.The Destination Connection ID of the client's first Initial packet (after a Retry, of its first Initial with the Retry's token): on a server, the ID the connection was created for.booleanWhether the handshake has completed.booleanisOpen()Whether the connection is open.booleanWhether the TLS handshake resumed an earlier session from a ticket.booleanClient: whether data written now goes out as 0-RTT data, before the handshake completes.The key exchange group the handshake used.The local address the connection sends from: the endpoint's socket, a socket of its own after it migrated, or a server's preferred address once its client moved there.intThe largest datagram payloadsendDatagram(byte[])takes now.migrate(InetSocketAddress local) Client: moves the connection to a new local address (RFC 9000 section 9), waiting until it has.migrate(DatagramChannel channel) Client: moves the connection to a socket of the caller's, asmigrate(InetSocketAddress)does with one it binds.Opens a bidirectional stream, waiting while the peer's stream limit is reached.Opens a unidirectional (send-only) stream, waiting while the peer's stream limit is reached.The peer's certificate chain, end-entity first.rebind(InetSocketAddress local) Client: moves the connection to a new local address at once, without probing the path first, as quinn's endpoint does when it rebinds: packets leave from a UDP socket bound atlocalfrom now on, with a connection ID of the server's not used before when it gave one, and the server follows as it follows a NAT rebinding, validating the new path itself.byte[]Waits for a datagram from the peer.byte[]receiveDatagram(Duration timeout) Waits for a datagram from the peer, up to a timeout.The peer's address.voidsendDatagram(byte[] data) Sends an unreliable datagram (RFC 9221).The server name: the one a client connected to, or the client's SNI on a server.stats()A snapshot of the connection's statistics.toString()booleanStarts a key update (RFC 9001 section 6).version()The QUIC version in use.
-
Method Details
-
awaitHandshake
Waits for the handshake to complete: for a connection fromQuicClient.connectEarly(java.net.InetSocketAddress, java.lang.String, java.time.Duration)or one a server accepted with 0-RTT data. Returns at once for other connections.- Parameters:
timeout- how long to wait, or null for no limit- Returns:
- true if the handshake completed, false on timeout
- Throws:
QuicConnectionException- if the connection ended firstInterruptedIOException- if interrupted while waitingIOException
-
isHandshakeComplete
public boolean isHandshakeComplete()Whether the handshake has completed.- Returns:
- true once complete
-
isResumed
public boolean isResumed()Whether the TLS handshake resumed an earlier session from a ticket.- Returns:
- true if resumed (a client knows once the server answered)
-
earlyDataAccepted
public boolean earlyDataAccepted()Whether the server accepted 0-RTT data: on a client, known once the handshake completes; on a server, from the start.- Returns:
- true if accepted
-
isZeroRtt
public boolean isZeroRtt()Client: whether data written now goes out as 0-RTT data, before the handshake completes.- Returns:
- true while sending 0-RTT data
-
openBidirectionalStream
Opens a bidirectional stream, waiting while the peer's stream limit is reached. Nothing is sent until data is written.- Returns:
- the stream
- Throws:
QuicConnectionException- if the connection is goneInterruptedIOException- if interrupted while waitingIOException
-
openUnidirectionalStream
Opens a unidirectional (send-only) stream, waiting while the peer's stream limit is reached.- Returns:
- the stream
- Throws:
QuicConnectionException- if the connection is goneInterruptedIOException- if interrupted while waitingIOException
-
acceptStream
Waits for a stream the peer opened, bidirectional or unidirectional (receive-only).- Returns:
- the stream
- Throws:
QuicConnectionException- if the connection is goneInterruptedIOException- if interrupted while waitingIOException
-
sendDatagram
Sends an unreliable datagram (RFC 9221). When the send buffer is full the oldest queued datagrams are dropped.- Parameters:
data- the payload, at mostmaxDatagramSize()bytes- Throws:
QuicConnectionException- if the connection is goneIllegalStateException- if either side does not accept datagramsIllegalArgumentException- if the payload is too largeIOException- if the connection is gone
-
receiveDatagram
Waits for a datagram from the peer.- Returns:
- the payload
- Throws:
QuicConnectionException- if the connection is goneInterruptedIOException- if interrupted while waitingIOException
-
receiveDatagram
Waits for a datagram from the peer, up to a timeout.- Parameters:
timeout- how long to wait, or null to wait without a limit- Returns:
- the payload, or null if none arrived in time
- Throws:
QuicConnectionException- if the connection is goneInterruptedIOException- if interrupted while waitingIOException
-
maxDatagramSize
public int maxDatagramSize()The largest datagram payloadsendDatagram(byte[])takes now.- Returns:
- bytes, or -1 if the peer does not accept datagrams
-
updateKeys
public boolean updateKeys()Starts a key update (RFC 9001 section 6). Keys are also updated routinely.- Returns:
- true if an update started; false while the previous one is unconfirmed
-
close
Closes the connection with an application error code: CONNECTION_CLOSE is sent at once and streams fail. Data not yet acknowledged is abandoned; finish streams and wait for the peer's reply first to deliver it.- Parameters:
code- the application error codereason- the reason phrase
-
close
public void close()Closes the connection with code 0 and no reason.- Specified by:
closein interfaceAutoCloseable
-
awaitClosed
Waits until the connection has ended, for any reason.- Parameters:
timeout- how long to wait, or null for no limit- Returns:
- why it ended, or null on timeout
- Throws:
InterruptedIOException- if interrupted while waiting
-
isOpen
public boolean isOpen()Whether the connection is open.- Returns:
- false once it is closing or gone
-
closeReason
Why the connection ended.- Returns:
- the reason, or null while it is open
-
alpn
The application protocol agreed with ALPN.- Returns:
- the protocol
-
serverName
The server name: the one a client connected to, or the client's SNI on a server.- Returns:
- the name, or null if the client sent none
-
peerCertificates
The peer's certificate chain, end-entity first.- Returns:
- the chain; empty if the peer sent none (a client without a certificate)
-
cipherSuite
The negotiated cipher suite.- Returns:
- the suite
-
keyExchangeGroup
The key exchange group the handshake used.- Returns:
- the group
-
remoteAddress
The peer's address.- Returns:
- the address
-
localAddress
The local address the connection sends from: the endpoint's socket, a socket of its own after it migrated, or a server's preferred address once its client moved there.- Returns:
- the address
-
migrate
Client: moves the connection to a new local address (RFC 9000 section 9), waiting until it has. A UDP socket is bound atlocal; the connection probes the path from there to the server with PATH_CHALLENGE and a connection ID of the server's it has not used, and switches to the path when the server answers. Its streams carry on meanwhile on the old path; the old socket is closed once no connection uses it (a client's first socket then gives way to the new one for later connections). The congestion and RTT state carry over when only the port changes, and start over otherwise. A new port on the same address is what a NAT rebinding looks like to the server.- Parameters:
local- the address to bind, port 0 for an ephemeral port- Returns:
- the new local address, with its port
- Throws:
IOException- if the socket cannot be bound; if the connection cannot migrate (a server's, one still handshaking, one where either side disabled active migration, one whose server gave no unused connection ID, one on an endpoint without a socket); or if the server did not answer on the new path (the connection stays where it was)QuicConnectionException- if the connection ended meanwhile
-
migrate
Client: moves the connection to a socket of the caller's, asmigrate(InetSocketAddress)does with one it binds. The connection owns the channel from now on, and closes it when it no longer uses it.- Parameters:
channel- a bound socket- Returns:
- the new local address
- Throws:
IOException- if the channel is not bound, or asmigrate(InetSocketAddress)
-
rebind
Client: moves the connection to a new local address at once, without probing the path first, as quinn's endpoint does when it rebinds: packets leave from a UDP socket bound atlocalfrom now on, with a connection ID of the server's not used before when it gave one, and the server follows as it follows a NAT rebinding, validating the new path itself. Use it with servers that never answermigrate(java.net.InetSocketAddress)'s probe on any path (aioquic's queues the response on the probed path and sends only on its active one). The old socket is closed once no connection uses it.- Parameters:
local- the address to bind, port 0 for an ephemeral port- Returns:
- the new local address, with its port
- Throws:
IOException- if the socket cannot be bound, or the connection cannot migrate (as formigrate(java.net.InetSocketAddress), except that the server need not have given an unused connection ID)QuicConnectionException- if the connection ended meanwhile
-
initialDestinationId
The Destination Connection ID of the client's first Initial packet (after a Retry, of its first Initial with the Retry's token): on a server, the ID the connection was created for.- Returns:
- the ID
-
version
The QUIC version in use.- Returns:
- the version
-
stats
A snapshot of the connection's statistics. The connection keeps them as plain fields that its own thread updates, so taking a snapshot costs a hold of the connection's lock and nothing else does.- Returns:
- the statistics
-
toString
-