pub struct VCLConnection { /* private fields */ }Expand description
A secure VCL Protocol connection over UDP.
Each connection manages its own cryptographic state: independent send/receive hash chains, nonce tracking, shared secret, and Ed25519 key pair.
§Example — Server
use vcl_protocol::connection::VCLConnection;
#[tokio::main]
async fn main() {
let mut server = VCLConnection::bind("127.0.0.1:8080").await.unwrap();
server.accept_handshake().await.unwrap();
loop {
match server.recv().await {
Ok(packet) => println!("{}", String::from_utf8_lossy(&packet.payload)),
Err(e) => { eprintln!("{}", e); break; }
}
}
}§Example — Client
use vcl_protocol::connection::VCLConnection;
#[tokio::main]
async fn main() {
let mut client = VCLConnection::bind("127.0.0.1:0").await.unwrap();
client.connect("127.0.0.1:8080").await.unwrap();
client.send(b"Hello!").await.unwrap();
client.close().unwrap();
}Implementations§
Source§impl VCLConnection
impl VCLConnection
Sourcepub async fn bind(addr: &str) -> Result<Self, VCLError>
pub async fn bind(addr: &str) -> Result<Self, VCLError>
Bind a new VCL connection to a local UDP address.
Use "127.0.0.1:0" to let the OS assign a port (typical for clients).
§Errors
Returns VCLError::IoError if the socket cannot be bound.
Sourcepub fn subscribe(&mut self) -> Receiver<VCLEvent>
pub fn subscribe(&mut self) -> Receiver<VCLEvent>
Subscribe to connection events.
Returns an async mpsc::Receiver<VCLEvent> with a channel capacity of 64.
Call this before connect() or accept_handshake() to receive
the VCLEvent::Connected event.
Events are sent with try_send — if the channel is full, events are dropped silently.
Sourcepub fn set_timeout(&mut self, secs: u64)
pub fn set_timeout(&mut self, secs: u64)
Set the inactivity timeout in seconds (default: 60).
If no send() or recv() occurs within this duration,
the next operation returns VCLError::Timeout.
Set to 0 to disable the timeout.
Sourcepub fn get_timeout(&self) -> u64
pub fn get_timeout(&self) -> u64
Get the current inactivity timeout in seconds.
Sourcepub fn last_activity(&self) -> Instant
pub fn last_activity(&self) -> Instant
Get the Instant of the last send() or recv() activity.
Override the Ed25519 signing key with a pre-shared key.
⚠️ For testing only. Never use a pre-shared key in production.
Sourcepub async fn connect(&mut self, addr: &str) -> Result<(), VCLError>
pub async fn connect(&mut self, addr: &str) -> Result<(), VCLError>
Connect to a remote VCL server and perform the X25519 handshake.
After this returns Ok(()), the connection is ready to send() and recv().
Emits VCLEvent::Connected if subscribed.
§Errors
VCLError::IoError— socket or address errorVCLError::HandshakeFailed— key exchange failedVCLError::ExpectedServerHello— unexpected handshake message
Sourcepub async fn accept_handshake(&mut self) -> Result<(), VCLError>
pub async fn accept_handshake(&mut self) -> Result<(), VCLError>
Accept an incoming X25519 handshake from a client (server side).
Blocks until a ClientHello is received.
After this returns Ok(()), the connection is ready to send() and recv().
Emits VCLEvent::Connected if subscribed.
§Errors
VCLError::IoError— socket errorVCLError::HandshakeFailed— key exchange failedVCLError::ExpectedClientHello— unexpected handshake message
Sourcepub async fn send(&mut self, data: &[u8]) -> Result<(), VCLError>
pub async fn send(&mut self, data: &[u8]) -> Result<(), VCLError>
Encrypt, sign, and send a data packet to the peer.
§Errors
VCLError::ConnectionClosed— connection was closedVCLError::Timeout— inactivity timeout exceededVCLError::NoSharedSecret— handshake not completedVCLError::NoPeerAddress— peer address unknownVCLError::IoError— socket error
Sourcepub async fn ping(&mut self) -> Result<(), VCLError>
pub async fn ping(&mut self) -> Result<(), VCLError>
Send a ping to the peer to check liveness and measure round-trip latency.
The pong reply is handled transparently inside recv() — you never
see Pong packets directly. Subscribe to events to receive
VCLEvent::PongReceived { latency }.
⚠️ You must keep calling recv() for the pong to be processed.
§Errors
Same as send().
Sourcepub async fn rotate_keys(&mut self) -> Result<(), VCLError>
pub async fn rotate_keys(&mut self) -> Result<(), VCLError>
Initiate a mid-session key rotation using a fresh X25519 ephemeral exchange.
Sends our new public key to the peer (encrypted with the current key), waits for the peer’s new public key, and atomically switches to the new shared secret on both sides.
Emits VCLEvent::KeyRotated on success.
⚠️ The peer must be actively calling recv() during rotation.
⚠️ Do not call send() while rotate_keys() is awaiting a response.
§Errors
VCLError::ConnectionClosed/VCLError::TimeoutVCLError::ChainValidationFailed/VCLError::SignatureInvalidVCLError::HandshakeFailed— unexpected packet type in responseVCLError::InvalidPacket— malformed public key payload
Sourcepub async fn recv(&mut self) -> Result<VCLPacket, VCLError>
pub async fn recv(&mut self) -> Result<VCLPacket, VCLError>
Receive the next data packet from the peer.
Control packets (Ping, Pong, KeyRotation) are handled
transparently — this method loops internally until a Data packet arrives.
On success, packet.payload contains the decrypted data.
§Errors
VCLError::ConnectionClosed— connection was closedVCLError::Timeout— inactivity timeout exceededVCLError::ReplayDetected— duplicate sequence or nonceVCLError::ChainValidationFailed— hash chain brokenVCLError::SignatureInvalid— Ed25519 signature mismatchVCLError::CryptoError— decryption failedVCLError::IoError— socket error
Sourcepub fn close(&mut self) -> Result<(), VCLError>
pub fn close(&mut self) -> Result<(), VCLError>
Gracefully close the connection and clear all cryptographic state.
After calling close(), all further operations return VCLError::ConnectionClosed.
Emits VCLEvent::Disconnected if subscribed.
§Errors
Returns VCLError::ConnectionClosed if already closed.
Sourcepub fn get_public_key(&self) -> Vec<u8> ⓘ
pub fn get_public_key(&self) -> Vec<u8> ⓘ
Get the local Ed25519 public key (32 bytes).
Get the current X25519 shared secret, or None if the handshake
has not completed or the connection is closed.