The ACK (Acknowledgment) processing system has been integrated into the DTLS v1.3 handshake state machine to provide reliable message delivery during the handshake process. This integration ensures that handshake messages are properly acknowledged and retransmitted when necessary, improving reliability over unreliable transport layers.
Connection::handle_handshake_message()
├── HandshakeManager::process_message() // Process through reliability layer
├── handle_ack_message() // Handle ACK-specific logic
└── State machine transitions // Update connection state
The ACK processing is active during the following connection states:
WAIT_SERVER_HELLO
WAIT_ENCRYPTED_EXTENSIONS
WAIT_CERTIFICATE_OR_CERT_REQUEST
WAIT_CERTIFICATE_VERIFY
WAIT_SERVER_FINISHED
WAIT_CLIENT_CERTIFICATE
WAIT_CLIENT_CERTIFICATE_VERIFY
WAIT_CLIENT_FINISHED
ACK processing is disabled during:
INITIAL
(no handshake in progress)CONNECTED
(handshake complete)CLOSED
(connection terminated)1. Receive Handshake Message
├── Process through HandshakeManager (generates ACK automatically)
├── Update connection state based on message type
└── Continue handshake progression
2. Send Handshake Message
├── HandshakeManager tracks message for reliability
├── Message sent through transport layer
└── Start retransmission timer
3. Receive ACK Message
├── HandshakeManager processes ACK ranges
├── Update RTT calculations
├── Cancel retransmission timers
└── Clean up acknowledged messages
4. Timeout Processing
├── Check for unacknowledged messages
├── Apply exponential backoff
├── Retransmit messages or fail handshake
└── Update statistics
handle_ack_message()
: Process received ACK messagessend_handshake_message()
: Send messages through HandshakeManagershould_process_ack_for_state()
: Determine if ACKs should be processedprocess_handshake_timeouts()
: Handle retransmission timeouts// Initialize HandshakeManager with ACK support
protocol::HandshakeManager::Config handshake_config;
handshake_config.enable_ack_processing = true;
handshake_manager_ = std::make_unique<protocol::HandshakeManager>(handshake_config);
// Setup callbacks
auto send_callback = [this](const HandshakeMessage& message) -> Result<void> {
return send_handshake_message(message);
};
auto event_callback = [this](HandshakeEvent event, const std::vector<uint8_t>& data) {
// Map handshake events to connection events
};
Result<void> Connection::handle_ack_message(const protocol::ACK& ack_message) {
// State validation
if (!should_process_ack_for_state(state_)) {
return make_result(); // Ignore ACKs in inappropriate states
}
// HandshakeManager handles the actual processing
// Connection layer performs state-specific validation
update_last_activity();
return make_result();
}
Result<void> Connection::process_handshake_timeouts() {
if (!handshake_manager_ || !should_process_ack_for_state(state_)) {
return make_result();
}
auto timeout_result = handshake_manager_->process_timeouts();
if (!timeout_result) {
fire_event(ConnectionEvent::HANDSHAKE_FAILED);
return timeout_result;
}
return make_result();
}
ConnectionConfig config;
config.handshake_timeout = std::chrono::milliseconds(10000); // Max handshake time
config.retransmission_timeout = std::chrono::milliseconds(1000); // Initial RTO
config.max_retransmissions = 5; // Max retransmit attempts
HandshakeManager::Config handshake_config;
handshake_config.initial_timeout = config.retransmission_timeout;
handshake_config.max_timeout = config.handshake_timeout;
handshake_config.max_retransmissions = config.max_retransmissions;
handshake_config.enable_ack_processing = true;
handshake_config.max_flight_size = 10; // Max unacknowledged messages
HANDSHAKE_FAILED
: Critical timeout or error occurredRETRANSMISSION_NEEDED
: Message needs retransmissionERROR_OCCURRED
: General error in ACK processingstruct ConnectionStats {
std::chrono::milliseconds handshake_duration{0};
uint32_t handshake_retransmissions = 0;
uint64_t records_sent = 0;
uint64_t records_received = 0;
uint32_t protocol_errors = 0;
};
struct Statistics {
uint32_t messages_sent{0};
uint32_t messages_received{0};
uint32_t acks_sent{0};
uint32_t acks_received{0};
uint32_t retransmissions{0};
uint32_t messages_in_flight{0};
std::chrono::milliseconds current_rto{0};
};
// Create connection with ACK support
auto connection = Connection::create_client(config, crypto_provider, server_address);
connection->initialize();
// Start handshake (ACK processing happens automatically)
connection->start_handshake();
// Periodic timeout processing (should be called regularly)
while (handshake_in_progress) {
connection->process_handshake_timeouts();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
auto event_callback = [](ConnectionEvent event, const std::vector<uint8_t>& data) {
switch (event) {
case ConnectionEvent::HANDSHAKE_COMPLETED:
std::cout << "Handshake completed successfully with ACK support\n";
break;
case ConnectionEvent::HANDSHAKE_FAILED:
std::cout << "Handshake failed - may be due to ACK timeout\n";
break;
}
};
The integration includes comprehensive test examples:
ack_state_machine_example.cpp
: Demonstrates state machine integrationack_integration_test.cpp
: Tests reliability and retransmission featuresack_message_example.cpp
: Basic ACK message functionalityThe ACK processing integration provides robust reliability for DTLS v1.3 handshake messages while maintaining clean separation of concerns between the connection state machine and reliability mechanisms. The implementation follows DTLS v1.3 specifications and provides configurable parameters for different network environments.