The coquic::core layer is the lowest public API. It is a sans-I/O endpoint: the caller owns UDP sockets, address routing, timers, file I/O, and threading. CoQUIC consumes typed inputs and returns typed effects.
This is the foundation used directly by low-level integrations and indirectly by the coquic::quic facade. HTTP/3 work ultimately returns to this layer as QUIC connection inputs.
#include "coquic/core.h"Use core when the integration needs direct control over connection handles, route handles, timers, packets, and application effects.
Endpoint Configuration
core::EndpointConfig configures one endpoint:
role: client or server.supported_versions: QUIC versions, defaulting to version 1.verify_peer: peer certificate verification policy.retry_enabled: server retry policy.application_protocol: ALPN value.identity: server certificate and key material.transport: flow-control, PMTU, DATAGRAM, ACK, migration, grease, and congestion-control settings.zero_rtt: 0-RTT attempt/allow policy and application context.qlog: optional qlog output directory.tls_keylog_path: optional TLS key log output.emit_shared_receive_stream_data: receive-data ownership mode.enable_out_of_order_receive: opt-in sparse stream receive delivery with offsets.enable_packet_inspection: packet inspection effect emission.allow_peer_address_change: peer address migration policy.
core::TransportConfig contains the transport-level defaults. Important settings include idle timeout, UDP payload size, PMTU probing limits, connection ID limit, stream and connection flow-control windows, DATAGRAM frame size, and congestion-control algorithm.
Inputs
core::EndpointInput is a variant of:
OpenConnection: client connection creation.InboundDatagram: UDP payload received from the runtime.PathMtuUpdate: runtime PMTU observation.ConnectionCommand: application action for an existing connection.TimerExpired: runtime timer expiry.
Connection commands carry core::ConnectionInput, a variant of:
SendStreamDataSendDatagramDataResetStreamStopSendingCloseConnectionRequestKeyUpdateRequestConnectionMigration
Effects
Every endpoint method returns core::Result. A result contains:
effects: typed actions and events.next_wakeup: next timer deadline.local_error: synchronous local API error, if any.send_continuation_pending: more send work can be produced without waiting for network input.
core::Effect is a variant of:
SendDatagram: bytes the runtime must send on a UDP route.ReceiveStreamData: stream bytes delivered to the application, including stream offset and optional final-size metadata.ReceiveDatagramData: DATAGRAM frame payload delivered to the application.PeerResetStreamandPeerStopSending: peer stream-control signals.StateEvent: handshake-ready, handshake-confirmed, or failed state changes.ConnectionLifecycleEvent: connection created, accepted, or closed.PeerPreferredAddressAvailable: server preferred address advertisement.ResumptionStateAvailable: TLS resumption state for persistence.ZeroRttStatusEvent: 0-RTT attempt result.PacketInspection: optional decoded packet metadata and payload snapshots.NewTokenAvailable: address-validation token from the peer.
Use helper extractors when only one effect class matters:
auto datagrams = coquic::core::send_datagrams(result);
auto states = coquic::core::state_events(result);
auto streams = coquic::core::receive_stream_events(result);
auto datagram_events = coquic::core::receive_datagram_events(result);Example
#include "coquic/core.h"
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <vector>
std::vector<std::byte> bytes(std::initializer_list<std::uint8_t> values) {
std::vector<std::byte> out;
out.reserve(values.size());
for (auto value : values) {
out.push_back(static_cast<std::byte>(value));
}
return out;
}
void open_client_connection() {
coquic::core::Endpoint endpoint({
.role = coquic::core::Role::client,
.verify_peer = false,
.application_protocol = "coquic",
});
const auto now = coquic::core::Clock::now();
auto result = endpoint.open_connection(
coquic::core::OpenConnection{
.connection =
{
.source_connection_id = bytes({0xc1, 0x01}),
.initial_destination_connection_id = bytes({0x83, 0x41}),
.server_name = "localhost",
},
.initial_route_handle = 7,
},
now);
for (const auto &datagram : coquic::core::send_datagrams(result)) {
// Send datagram.bytes on the UDP route identified by datagram.route_handle.
}
}Diagnostics
Endpoint::connection_diagnostics() returns lightweight connection state for debug views and tests. It includes handshake status, current version, active paths, active streams, and retired streams. Diagnostics are observability data, not protocol commands.