use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error, warn};
use crate::api::common::error::SecurityError;
use crate::api::server::security::srtp::keys;
use crate::dtls::{handshake::HandshakeStep, DtlsConnection};
use crate::srtp::SrtpContext;
pub async fn process_handshake_step(
conn: &mut DtlsConnection,
step: HandshakeStep,
address: SocketAddr,
handshake_completed: &Arc<Mutex<bool>>,
srtp_context: &Arc<Mutex<Option<SrtpContext>>>,
) -> Result<(), SecurityError> {
debug!("Current handshake step: {:?}", step);
match step {
HandshakeStep::SentHelloVerifyRequest => {
debug!("Server sent HelloVerifyRequest, waiting for ClientHello with cookie");
}
HandshakeStep::ReceivedClientHello => {
debug!("Server received ClientHello, sending ServerHello");
if let Err(e) = conn.continue_handshake().await {
warn!("Failed to continue handshake after ClientHello: {}", e);
} else {
debug!("Successfully sent ServerHello after ClientHello");
}
}
HandshakeStep::ReceivedClientKeyExchange => {
debug!("Server received ClientKeyExchange, sending ChangeCipherSpec and Finished");
if let Err(e) = conn.continue_handshake().await {
warn!(
"Failed to continue handshake after ClientKeyExchange: {}",
e
);
} else {
debug!("Successfully completed handshake from server side");
}
}
HandshakeStep::Complete => {
debug!("Server handshake complete with client {}", address);
let mut completed = handshake_completed.lock().await;
if !*completed {
*completed = true;
match keys::extract_srtp_keys(conn, address, false).await {
Ok(ctx) => {
let mut srtp_guard = srtp_context.lock().await;
*srtp_guard = Some(ctx);
debug!(
"Server successfully extracted SRTP keys for client {}",
address
);
}
Err(e) => warn!("Failed to extract SRTP keys: {}", e),
}
}
}
_ => {} }
Ok(())
}
pub async fn start_handshake(
conn: &mut DtlsConnection,
address: SocketAddr,
) -> Result<(), SecurityError> {
debug!("Starting DTLS handshake with client {}", address);
match conn.start_handshake(address).await {
Ok(_) => Ok(()),
Err(e) => Err(SecurityError::Handshake(format!(
"Failed to start DTLS handshake: {}",
e
))),
}
}
pub async fn wait_for_handshake(
connection: &Arc<Mutex<Option<DtlsConnection>>>,
address: SocketAddr,
handshake_completed: &Arc<Mutex<bool>>,
srtp_context: &Arc<Mutex<Option<SrtpContext>>>,
) -> Result<(), SecurityError> {
debug!(
"Waiting for DTLS handshake completion for client {}",
address
);
let conn_result = {
let mut conn_guard = connection.lock().await;
match conn_guard.as_mut() {
Some(conn) => conn.wait_handshake().await,
None => {
error!("No DTLS connection for client {}", address);
return Err(SecurityError::NotInitialized(
"DTLS connection not initialized".to_string(),
));
}
}
};
match conn_result {
Ok(_) => {
debug!("DTLS handshake completed for client {}", address);
let conn_guard = connection.lock().await;
if let Some(conn) = conn_guard.as_ref() {
match keys::extract_srtp_keys(conn, address, false).await {
Ok(srtp_ctx) => {
debug!("Created SRTP context for client {}", address);
let mut srtp_guard = srtp_context.lock().await;
*srtp_guard = Some(srtp_ctx);
let mut completed = handshake_completed.lock().await;
*completed = true;
debug!("DTLS handshake fully completed for client {}", address);
Ok(())
}
Err(e) => {
error!("Failed to extract SRTP keys for client {}: {}", address, e);
Err(e)
}
}
} else {
Err(SecurityError::NotInitialized(
"DTLS connection not available".to_string(),
))
}
}
Err(e) => {
error!("DTLS handshake failed for client {}: {}", address, e);
Err(SecurityError::Handshake(format!(
"DTLS handshake failed: {}",
e
)))
}
}
}
pub async fn process_dtls_packet(
conn: &mut DtlsConnection,
data: &[u8],
address: SocketAddr,
handshake_completed: &Arc<Mutex<bool>>,
srtp_context: &Arc<Mutex<Option<SrtpContext>>>,
) -> Result<(), SecurityError> {
debug!(
"Server processing DTLS packet of {} bytes from client {}",
data.len(),
address
);
match conn.process_packet(data).await {
Ok(_) => {
if let Some(step) = conn.handshake_step() {
process_handshake_step(conn, step, address, handshake_completed, srtp_context)
.await?;
}
Ok(())
}
Err(e) => {
debug!("Error processing DTLS packet: {}", e);
if e.to_string().contains("Invalid cookie") {
debug!("Cookie validation failed, restarting handshake");
if let Err(restart_err) = conn.start_handshake(address).await {
warn!("Failed to restart handshake: {}", restart_err);
}
}
Ok(())
}
}
}