# ant-quic API Reference
This document provides a comprehensive API reference for ant-quic v0.13.0+.
## Table of Contents
1. [Primary API: P2pEndpoint](#primary-api-p2pendpoint)
2. [Configuration](#configuration)
3. [NAT Traversal](#nat-traversal)
4. [Transport Parameters](#transport-parameters)
5. [Extension Frames](#extension-frames)
6. [Events](#events)
7. [Error Handling](#error-handling)
8. [Code Examples](#code-examples)
## Primary API: P2pEndpoint
The primary entry point for all P2P operations. All nodes are symmetric - every node can both initiate and accept connections.
`P2pEndpoint` is the canonical connectivity surface. `Node` is a convenience façade over the same endpoint-level behavior for applications that want a simpler top-level API.
### Creating an Endpoint
```rust
use ant_quic::{P2pEndpoint, P2pConfig};
// Simple endpoint
let config = P2pConfig::builder()
.known_peer("quic.saorsalabs.com:9000".parse()?)
.build()?;
let endpoint = P2pEndpoint::new(config).await?;
// With custom configuration
let config = P2pConfig::builder()
.bind_addr("0.0.0.0:9000".parse()?)
.known_peer("peer1.example.com:9000".parse()?)
.known_peer("peer2.example.com:9000".parse()?)
.max_connections(100)
.build()?;
let endpoint = P2pEndpoint::new(config).await?;
```
### Connecting to Peers
```rust
// Seed connectivity from configured known peers
endpoint.connect_known_peers().await?;
// Connect to a specific address through the unified outbound path
let connection = endpoint.connect_addr(peer_addr).await?;
// Connect to an authenticated peer identity
let connection = endpoint.connect_peer(peer_id).await?;
// Advanced: connect by peer identity plus explicit address hints
let connection = endpoint.connect_peer_with_addrs(peer_id, candidate_addrs).await?;
// Advanced: continuously merge higher-layer discovery hints
let capabilities = ant_quic::bootstrap_cache::PeerCapabilities {
supports_coordination: true,
..Default::default()
};
endpoint
.upsert_peer_hints(peer_id, candidate_addrs, Some(capabilities))
.await;
```
`connect_addr()` is not a separate direct-only strategy. It is the canonical address-based connect entrypoint and goes through the endpoint's normal routing/orchestration path, including connection reuse, direct establishment, and fallback handling when applicable. Richer peer-oriented behavior comes from `connect_known_peers()` and `connect_peer()`.
`connect_peer_with_addrs()` is the advanced variant for higher layers that already have a durable `PeerId` plus candidate socket addresses from imported peer cards, peer caches, or external discovery. It still uses the same authenticated orchestration path as `connect_peer()`; the address list is only a dialing hint.
`upsert_peer_hints()` is the advanced discovery bridge for callers that learn peer addresses or assist-role hints (for example from imported cards, caches, gossip, or rendezvous). It merges that metadata into both ant-quic's live runtime view and the persisted bootstrap cache while keeping actual path selection inside the transport. Explicit assist-role hints remain advisory claims; separately tracked direct reachability evidence still determines the stronger peer-verified path quality signals.
### Accepting Connections
```rust
// Accept incoming connections (all endpoints can accept)
while let Some(conn) = endpoint.accept().await {
tokio::spawn(async move {
handle_connection(conn).await;
});
}
```
### Working with Streams
```rust
// Bidirectional stream
let (mut send, mut recv) = connection.open_bi().await?;
send.write_all(b"Hello").await?;
send.finish()?;
let response = recv.read_to_end(4096).await?;
// Unidirectional stream
let mut send = connection.open_uni().await?;
send.write_all(b"Data").await?;
send.finish()?;
```
## Configuration
### P2pConfig Builder
```rust
let config = P2pConfig::builder()
.bind_addr(SocketAddr) // Local address to bind
.known_peer(SocketAddr) // Known peer contact hint for initial connectivity (repeatable)
.nat(NatConfig) // NAT traversal configuration
.pqc(PqcConfig) // Post-quantum crypto configuration
.mtu(MtuConfig) // MTU configuration
.max_connections(usize) // Maximum concurrent connections
.build()?;
```
Known peers are seed inputs into the symmetric peer graph. They are not privileged bootstrap servers and do not imply a separate protocol role.
`SocketAddr` values in configuration are contact hints only. Durable peer identity
is always `PeerId`, derived from the authenticated ML-DSA-65 public key.
### DiscoveryPolicy and MdnsConfig
Scoped first-party mDNS is always available and defaults to enabled
zero-config discovery for non-loopback endpoints:
```rust
use ant_quic::unified_config::{
AutoConnectPolicy, DiscoveryPolicy, MdnsConfig, MdnsMode,
};
let config = P2pConfig::builder()
.discovery(DiscoveryPolicy {
static_known_peers: true,
mdns: Some(MdnsConfig {
enabled: true,
service: Some("ant-quic".into()),
namespace: Some("workspace-a".into()),
mode: MdnsMode::Both,
auto_connect: AutoConnectPolicy::Enabled,
metadata: std::collections::BTreeMap::new(),
}),
auto_connect: AutoConnectPolicy::Enabled,
})
.build()?;
```
mDNS records are locator claims only. The authenticated QUIC handshake remains
the durable source of truth for `PeerId`.
Nodes advertise relay/bootstrap/coordinator capability hints by default.
Those hints are policy claims only; authenticated identity and runtime
performance still decide whether a peer should actually use them.
### NatConfig
```rust
pub struct NatConfig {
pub port_mapping: PortMappingConfig,
pub max_candidates: usize,
pub enable_symmetric_nat: bool,
pub enable_relay_fallback: bool,
pub enable_relay_service: bool,
pub relay_nodes: Vec<SocketAddr>,
pub max_concurrent_attempts: usize,
pub prefer_rfc_nat_traversal: bool,
}
```
Several NAT fields are now effectively always-on in symmetric mode. They remain configurable for compatibility and tuning, but normal endpoint dialing uses one unified orchestration path rather than user-selected fallback strategies.
`port_mapping` is the additive best-effort router-assist policy. The current
runtime uses UPnP IGD internally, starts after the bound UDP port is known,
renews leases in the background, and never blocks endpoint startup.
### PortMappingConfig
```rust
pub struct PortMappingConfig {
pub enabled: bool, // default: true
pub lease_duration_secs: u32, // default: 3600
pub allow_random_external_port: bool, // default: true
}
```
Common ergonomic entrypoint:
```rust
let config = P2pConfig::builder()
.port_mapping_enabled(false)
.build()?;
```
### PqcConfig
PQC is always enabled. These options tune PQC behavior:
```rust
let pqc = PqcConfig::builder()
.ml_kem(true) // Enable ML-KEM-768 (default: true)
.ml_dsa(true) // Enable ML-DSA-65 (default: true)
.memory_pool_size(10) // Buffer pool size (default: 10)
.handshake_timeout_multiplier(1.5) // Timeout multiplier (default: 1.5)
.build()?;
```
### MtuConfig
```rust
pub struct MtuConfig {
pub initial: u16, // Initial MTU (default: 1200)
pub min: u16, // Minimum MTU (default: 1200)
pub max: u16, // Maximum MTU (default: 1500)
}
```
## NAT Traversal
### Address Discovery
```rust
// Connect to known peers and allow external address observation
endpoint.connect_known_peers().await?;
// Connect to a specific address through the canonical address entrypoint
let _connection = endpoint.connect_addr(target_addr).await?;
// Get discovered external address
let external: Option<SocketAddr> = endpoint.external_addr();
// Port mapping contributes an extra external candidate when active
let mapped: Option<SocketAddr> = endpoint.port_mapping_addr();
let all_candidates: Vec<SocketAddr> = endpoint.all_external_addrs();
// Query first-party mDNS browse/advertise state
let mdns = endpoint.mdns_snapshot();
let mdns_peer_count = mdns.discovered_peers.len();
// Query assist-role capability hints
let relay_service_enabled = endpoint.relay_service_enabled();
let coordinator_service_enabled = endpoint.coordinator_service_enabled();
let bootstrap_service_enabled = endpoint.bootstrap_service_enabled();
```
Address discovery primarily comes from seeded peer connectivity. Applications generally call `connect_known_peers()` to establish that context, then use `connect_addr()` for address-based dialing or `connect_peer()` for peer-oriented dialing while the endpoint applies its normal routing/orchestration behavior.
### CandidateAddress
```rust
pub struct CandidateAddress {
pub addr: SocketAddr,
pub source: CandidateSource,
pub priority: u32,
}
pub enum CandidateSource {
Local, // Interface address
Observed, // Via OBSERVED_ADDRESS frame
Predicted, // Symmetric NAT port prediction
}
```
## Transport Parameters
### NAT Traversal Capability
| `0x3d7e9f0bca12fea6` | NAT traversal capability indicator |
| `0x3d7e9f0bca12fea8` | RFC-compliant frame format support |
| `0x9f81a176` | Address discovery configuration |
## Extension Frames
### ADD_ADDRESS Frame
Advertises address candidates to peer.
```
Type: 0x3d7e90 (IPv4), 0x3d7e91 (IPv6)
Format:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address (4/16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Port (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
### PUNCH_ME_NOW Frame
Coordinates hole punching timing.
```
Type: 0x3d7e92 (IPv4), 0x3d7e93 (IPv6)
Format:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Target IP Address (4/16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Target Port (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
### REMOVE_ADDRESS Frame
```
Type: 0x3d7e94
Format:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
### OBSERVED_ADDRESS Frame
Reports observed external address to peer.
```
Type: 0x9f81a6 (IPv4), 0x9f81a7 (IPv6)
Format:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Observed IP Address (4/16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Observed Port (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
## Events
Relevant structured endpoint events now include:
- `ExternalAddressDiscovered`
- `PortMappingEstablished`
- `PortMappingRenewed`
- `PortMappingFailed`
- `PortMappingRemoved`
- `MdnsServiceAdvertised`
- `MdnsPeerDiscovered`
- `MdnsPeerUpdated`
- `MdnsPeerRemoved`
- `MdnsPeerEligible`
- `MdnsPeerIneligible`
- `MdnsAutoConnectAttempted`
- `MdnsAutoConnectSucceeded`
- `MdnsAutoConnectFailed`
These endpoint events are mirrored through `NodeEvent` on the higher-level
`Node` API.
### P2pEvent
```rust
pub enum P2pEvent {
// Connection lifecycle
Connected { peer_id: PeerId, addr: SocketAddr },
Disconnected { peer_id: PeerId, reason: String },
ConnectionFailed { peer_id: PeerId, reason: String },
// Address discovery
AddressDiscovered { addr: SocketAddr },
AddressChanged { old: SocketAddr, new: SocketAddr },
// NAT traversal
HolePunchStarted { peer_id: PeerId },
HolePunchSucceeded { peer_id: PeerId, addr: SocketAddr },
HolePunchFailed { peer_id: PeerId, reason: String },
// Candidates
CandidatesDiscovered { peer_id: PeerId, count: usize },
}
```
### Event Handling
```rust
let mut events = endpoint.subscribe();
while let Ok(event) = events.recv().await {
match event {
P2pEvent::Connected { peer_id, addr } => {
println!("Connected to {} at {}", peer_id.to_hex(), addr);
}
P2pEvent::AddressDiscovered { addr } => {
println!("External address: {}", addr);
}
P2pEvent::HolePunchSucceeded { peer_id, addr } => {
println!("Direct connection to {}", peer_id.to_hex());
}
_ => {}
}
}
```
## Error Handling
### EndpointError
```rust
pub enum EndpointError {
BindFailed(std::io::Error),
ConnectionFailed(String),
Timeout,
InvalidConfiguration(String),
// ...
}
```
### NatTraversalError
```rust
pub enum NatTraversalError {
NoViableCandidates,
CoordinationTimeout,
HolePunchFailed(String),
// ...
}
```
## Code Examples
### Complete P2P Node
```rust
use ant_quic::{NatConfig, P2pConfig, P2pEndpoint, P2pEvent, PortMappingConfig};
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Configure endpoint
let config = P2pConfig::builder()
.bind_addr("0.0.0.0:9000".parse()?)
.known_peer("quic.saorsalabs.com:9000".parse()?)
.nat(NatConfig {
port_mapping: PortMappingConfig::default(),
max_candidates: 15,
enable_symmetric_nat: true,
..Default::default()
})
.max_connections(100)
.build()?;
// Create endpoint
let endpoint = P2pEndpoint::new(config).await?;
println!("Peer ID: {}", endpoint.peer_id().to_hex());
// Seed peer connectivity and external address observation
endpoint.connect_known_peers().await?;
if let Some(addr) = endpoint.external_addr() {
println!("External: {}", addr);
}
if let Some(mapped) = endpoint.port_mapping_addr() {
println!("Router-mapped candidate: {}", mapped);
}
// Subscribe to events
let mut events = endpoint.subscribe();
let ep = endpoint.clone();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
println!("Event: {:?}", event);
}
});
// Accept connections (all nodes can accept)
while let Some(conn) = endpoint.accept().await {
tokio::spawn(async move {
// Handle streams
while let Ok((send, recv)) = conn.accept_bi().await {
// Echo server
let data = recv.read_to_end(4096).await?;
send.write_all(&data).await?;
send.finish()?;
}
Ok::<_, anyhow::Error>(())
});
}
Ok(())
}
```
### Statistics Monitoring
```rust
let stats = endpoint.stats().await;
println!("Active connections: {}", stats.active_connections);
println!("Discovered addresses: {}", stats.discovered_addresses);
println!("Successful punches: {}", stats.successful_hole_punches);
println!("Failed punches: {}", stats.failed_hole_punches);
println!("Bytes sent: {}", stats.bytes_sent);
println!("Bytes received: {}", stats.bytes_received);
println!("Port mapping active: {}", endpoint.port_mapping_active());
println!("Port mapping addr: {:?}", endpoint.port_mapping_addr());
```
## Removed API (v0.13.0)
The following types were **removed** in v0.13.0:
| `QuicNodeConfig` | Use `P2pConfig` |
| `QuicP2PNode` | Use `P2pEndpoint` |
| `EndpointRole` | All nodes are symmetric |
| `NatTraversalRole` | All nodes are symmetric |
| `PqcMode` | PQC always enabled |
| `HybridPreference` | No mode selection |
| `bootstrap_nodes` | Use `known_peer()` / `known_peers()` seed inputs |
## Support
- GitHub Issues: https://github.com/dirvine/ant-quic/issues
- Documentation: https://docs.rs/ant-quic
- Examples: https://github.com/dirvine/ant-quic/tree/main/examples