NAME
Net::QUIC::Connection - one QUIC connection
DESCRIPTION
A Connection is one secure QUIC relationship with a peer.
It can contain many independent Net::QUIC::Stream objects.
Application protocol code normally works with Connection and Stream. UDP socket and timer handling normally stays in Net::QUIC::Driver.
A client Driver has one Connection.
A server Driver can create many Connections.
BASIC USE
Get the client Connection:
my $connection = $driver->connection;
Wait for the handshake:
return if !$connection->ready;
Open a bidirectional Stream:
my $stream = $connection->open_bidi_stream;
if ($stream) {
$stream->send("hello");
$stream->finish;
}
Accept Streams opened by the peer:
while (my $stream = $connection->next_stream) {
...
}
Close normally:
$connection->close;
HANDSHAKE AND SAVED STATE
ready
if ($connection->ready) {
...
}
Returns true after the QUIC/TLS handshake is ready for normal application work.
A server can expose a Connection before this becomes true.
client_chosen_version
my $version = $connection->client_chosen_version;
Returns 1 or 2 for the QUIC version used by the client's first Initial packet.
This can differ from "version" when Compatible Version Negotiation switches the connection to another supported version during the handshake.
version
my $version = $connection->version;
Returns the final negotiated QUIC version, 1 or 2.
It can be undef before version negotiation is complete.
Most applications do not need to branch on this value.
session_ticket
my $ticket = $connection->session_ticket;
Returns the newest opaque TLS session ticket received by the client, or undef if none is available.
A later client can pass it as:
session_ticket => $ticket
to attempt a faster resumed TLS handshake.
Treat the ticket as opaque bytes.
If it is expired or otherwise unusable, the connection falls back to a normal full handshake.
resumed
if ($connection->resumed) {
...
}
Returns true when the completed TLS handshake actually resumed a previous session.
address_token
my $token = $connection->address_token;
Returns the newest opaque QUIC address-validation token received by the client, or undef if none is available.
A later client can pass it as:
address_token => $token
A valid token can let a server with address validation enabled accept the new connection without another Retry round trip.
Treat the token as opaque bytes.
early_data_state
my $state = $connection->early_data_state;
Returns one opaque value that a client can save for a later 0-RTT attempt.
A later client supplies it as:
early_data => $state
0-RTT allows some application data to be sent before the new handshake completes.
0-RTT data can be replayed. Only use it for operations that are safe to repeat.
early_data_status
my $status = $connection->early_data_status;
Returns one of:
none
pending
accepted
rejected
pending means this client is attempting 0-RTT and does not yet know whether the server accepted it.
If 0-RTT is rejected, the normal TLS handshake can still complete.
Streams created for the rejected early-data attempt become invalid. Open new Streams after ready and resend only operations that are safe to repeat.
OPENING STREAMS
open_bidi_stream
my $stream = $connection->open_bidi_stream;
Opens a bidirectional Stream.
Both endpoints can send on a bidirectional Stream.
Returns undef when the peer's current bidirectional stream limit has been reached.
That is normal QUIC flow control, not a Connection failure.
open_uni_stream
my $stream = $connection->open_uni_stream;
Opens a unidirectional Stream.
Only this endpoint can send application bytes on a locally opened unidirectional Stream.
Returns undef when the peer's current unidirectional stream limit has been reached.
on_stream_available
$connection->on_stream_available(sub {
my ($connection, $type) = @_;
...
});
Registers a callback for new local stream credit.
$type is:
bidi
or:
uni
Use this when open_bidi_stream or open_uni_stream returned undef and the application wants to try again when the peer allows another Stream.
PEER-CREATED STREAMS
next_stream
while (my $stream = $connection->next_stream) {
...
}
Returns the next Stream opened by the peer.
Returns undef when no new peer-created Stream is waiting.
A Stream can be bidirectional or unidirectional. Use:
$stream->can_send
$stream->can_receive
when code needs to handle either kind.
on_stream_activity
$connection->on_stream_activity(sub {
my ($connection) = @_;
...
});
Registers an advanced protocol-engine wake-up callback.
The callback runs when one or more Streams have meaningful new activity, such as received data, FIN, acknowledgement progress, RESET_STREAM, STOP_SENDING, stream close, or a newly peer-created Stream.
The callback does not receive one event object per transport event. Activity is coalesced by Stream.
Drain the changed Stream IDs with "next_active_stream_id".
Pass undef to disable activity tracking:
$connection->on_stream_activity(undef);
Activity tracking is opt-in so ordinary applications pay no queueing cost.
next_active_stream_id
while (defined(my $id = $connection->next_active_stream_id)) {
...
}
Returns the next Stream ID with coalesced activity.
Returns undef when the activity queue is empty.
A protocol engine should normally drain this queue when "on_stream_activity" wakes it. State such as received data, acknowledgement offsets, reset codes, and STOP_SENDING codes remains available on the corresponding Stream object.
QUIC DATAGRAM
RFC 9221 QUIC DATAGRAM carries unreliable application bytes inside a Connection.
This is different from Net::QUIC::Datagram. That class represents one UDP packet that the event-loop adapter must send. The methods in this section represent application DATAGRAM frames carried inside QUIC.
DATAGRAM support is directional.
This endpoint advertises its receive limit with the Endpoint transport option:
transport => {
max_datagram_frame_size => 65535,
}
The default is zero, which disables receiving QUIC DATAGRAM.
can_send_datagram
if ($connection->can_send_datagram) {
...
}
Returns true when the peer advertised a nonzero QUIC DATAGRAM receive limit.
can_receive_datagram
if ($connection->can_receive_datagram) {
...
}
Returns true when this endpoint advertised a nonzero QUIC DATAGRAM receive limit.
peer_max_datagram_frame_size
my $bytes = $connection->peer_max_datagram_frame_size;
Returns the peer's advertised max_datagram_frame_size transport parameter.
It can be undef before peer transport parameters are available.
local_max_datagram_frame_size
my $bytes = $connection->local_max_datagram_frame_size;
Returns this endpoint's advertised max_datagram_frame_size.
max_datagram_payload_size
my $bytes = $connection->max_datagram_payload_size;
Returns a conservative maximum application payload that can currently fit in one QUIC DATAGRAM on the active path.
It accounts for both the peer's DATAGRAM frame limit and the current QUIC path UDP payload ceiling. The value can change after PMTU discovery or path migration.
A protocol layered above QUIC must subtract its own framing bytes from this value.
send_datagram
my $accepted = $connection->send_datagram($bytes);
Queues one unreliable QUIC DATAGRAM.
Returns true when Net::QUIC copied the payload into its bounded pending slot. Returns false when that one pending slot is already occupied.
A true return value does not mean the peer received the DATAGRAM. Lost QUIC DATAGRAMs are not retransmitted.
The method throws if the peer did not negotiate DATAGRAM receive support, the payload is too large, the Connection is closing, or the handshake is not ready and no saved 0-RTT state is active.
A client using saved "early_data_state" may send DATAGRAM in 0-RTT when the saved peer transport parameters permit it. 0-RTT data can be replayed, so only send operations that are safe to repeat and check "early_data_status" after the handshake.
next_received_datagram
my $bytes = $connection->next_received_datagram;
or:
my ($bytes, $early_data) = $connection->next_received_datagram;
Returns the next received QUIC DATAGRAM, or undef when none is waiting.
In scalar context it returns only the payload bytes. In list context it also returns a boolean that is true when the DATAGRAM was received as 0-RTT early data.
A zero-length DATAGRAM is returned as an empty string. Test the result with defined, not truth.
Received DATAGRAMs are kept in a bounded native fallback queue until pulled or dispatched. Additional unreliable DATAGRAMs are dropped when that queue is full.
on_datagram
$connection->on_datagram(sub {
my ($connection, $bytes, $early_data) = @_;
...
});
Registers a callback for received QUIC DATAGRAM payloads.
Callbacks run after native QUIC packet processing returns. They are not called from inside the ngtcp2 receive callback.
The callback drains the same queue used by "next_received_datagram".
Disable it with:
$connection->on_datagram(undef);
datagram_receive_drops
my $count = $connection->datagram_receive_drops;
Returns the number of received QUIC DATAGRAM payloads dropped because the bounded receive queue was full.
BOUNDED TRANSMIT BUFFERING
These methods are for advanced producers that need a hard bound on Stream data retained by Net::QUIC.
send_buffer_limit
$connection->send_buffer_limit(4 * 1024 * 1024);
Enables a connection-wide limit on retained Stream transmit bytes.
The limit counts Stream data that is queued for sending plus data already sent but still retained until peer acknowledgement.
Use:
my $limit = $connection->send_buffer_limit;
to read the current limit.
It returns undef when bounded transmit mode is disabled.
Disable the limit with:
$connection->send_buffer_limit(undef);
A new limit cannot be smaller than the amount of Stream data already retained.
When a limit is enabled, ordinary "send" in Net::QUIC::Stream remains all-or-nothing. It throws instead of exceeding the configured bound. Advanced producers should use "send_some" in Net::QUIC::Stream.
send_buffered_bytes
my $bytes = $connection->send_buffered_bytes;
Returns the total number of Stream data bytes currently retained for transmit across this Connection.
This includes sent data that still has to remain available until it is acknowledged.
NETWORK PATH
A QUIC Connection can survive some network-address changes without being recreated.
Most applications do not need to inspect path state during ordinary use.
path
my $path = $connection->path;
Returns the active network path:
{
local => $packed_local_address,
peer => $packed_peer_address,
}
migrate
$connection->migrate($new_packed_local_address);
Client only.
Starts migration to another local address while keeping the same QUIC Connection.
Net::QUIC validates the new path before switching to it.
If validation fails, the previous working path stays active.
path_validation_status
my $status = $connection->path_validation_status;
Returns:
none
validating
succeeded
failed
aborted
This is the simple path-validation view.
path_validation
my $info = $connection->path_validation;
Returns the detailed current or most recent path-validation state.
The hash includes at least:
status
and, when a validation has occurred:
local
peer
It also reports whether the validation was associated with a server preferred address or a fresh address-validation token.
path_max_udp_payload_size
my $bytes = $connection->path_max_udp_payload_size;
Returns the currently discovered maximum UDP payload size for the active path.
A new path starts at QUIC's safe 1200-byte baseline. The native QUIC engine can raise this value when larger packets work.
This is mainly diagnostic. Applications normally do not need to manage PMTU discovery themselves.
CLOSING
close
$connection->close;
or:
$connection->close($application_error_code);
Starts a normal application-level QUIC close.
The default application error code is zero.
Closing is not immediate destruction. QUIC has a short closing/draining period so late packets can still be handled correctly.
closed
if ($connection->closed) {
...
}
Returns true when the Connection no longer needs network or timer service.
CLOSE AND ERROR INFORMATION
close_info
my $info = $connection->close_info;
Returns undef while no close or failure has been recorded.
Otherwise it returns a hash describing the outcome.
For example, a normal peer application close can look like:
{
type => 'application',
initiator => 'peer',
code => 0,
}
type can be:
application
transport
tls
certificate
handshake
idle
drop
initiator is:
local
peer
code is the application error code, QUIC transport error code, or TLS alert code as appropriate.
A peer transport error can also include frame_type.
A locally detected native transport failure can include native_error.
Remote protocol errors, certificate failures, handshake failures, idle timeout, and normal closes are Connection outcomes rather than ordinary Perl exceptions.
Local programming mistakes, invalid configuration, allocation failure, and internal implementation failures still throw Perl exceptions.
DRIVER NOTIFICATION
Connections obtained through Net::QUIC::Driver automatically notify Driver when application operations create new transport work.
For example:
$stream->send(...);
$stream->finish;
$stream->reset(...);
$connection->close;
do not require a separate service or pump call.