use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error};
use crate::api::client::security::create_dtls_config as api_create_dtls_config;
use crate::api::client::security::ClientSecurityConfig;
use crate::api::common::error::SecurityError;
use crate::api::server::security::SocketHandle;
use crate::dtls::transport::udp::UdpTransport;
use crate::dtls::{DtlsConfig, DtlsConnection, DtlsRole, DtlsVersion};
use crate::srtp::SRTP_AES128_CM_SHA1_80;
use tokio::net::UdpSocket;
pub async fn init_connection(
config: &ClientSecurityConfig,
socket: &Arc<Mutex<Option<SocketHandle>>>,
connection: &Arc<Mutex<Option<DtlsConnection>>>,
) -> Result<(), SecurityError> {
let socket_guard = socket.lock().await;
let socket = socket_guard.clone().ok_or_else(|| {
SecurityError::Configuration("No socket set for security context".to_string())
})?;
drop(socket_guard);
if config.srtp_profiles.is_empty() {
return Err(SecurityError::Configuration(
"No SRTP profiles specified".to_string(),
));
}
let dtls_config = api_create_dtls_config(config);
let mut connection_obj = DtlsConnection::new(dtls_config);
let cert = if let (Some(cert_path), Some(key_path)) =
(&config.certificate_path, &config.private_key_path)
{
debug!(
"Loading certificate from {} and key from {}",
cert_path, key_path
);
let _cert_data = match std::fs::read_to_string(cert_path) {
Ok(data) => data,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to read certificate file {}: {}",
cert_path, e
)))
}
};
let _key_data = match std::fs::read_to_string(key_path) {
Ok(data) => data,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to read private key file {}: {}",
key_path, e
)))
}
};
debug!("PEM files found but using generated certificate for now");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to generate certificate: {}",
e
)))
}
}
} else {
debug!("Generating self-signed certificate with proper crypto parameters");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to generate certificate: {}",
e
)))
}
}
};
connection_obj.set_certificate(cert);
let transport =
match crate::dtls::transport::udp::UdpTransport::new(socket.socket.clone(), 1500).await {
Ok(t) => t,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to create DTLS transport: {}",
e
)))
}
};
let transport = Arc::new(Mutex::new(transport));
let start_result = transport.lock().await.start().await;
if start_result.is_ok() {
debug!("DTLS transport started successfully");
connection_obj.set_transport(transport);
let mut conn_guard = connection.lock().await;
*conn_guard = Some(connection_obj);
Ok(())
} else {
let err = start_result.err().unwrap();
error!("Failed to start DTLS transport: {}", err);
Err(SecurityError::Configuration(format!(
"Failed to start DTLS transport: {}",
err
)))
}
}
pub async fn create_connection(
socket: &Arc<UdpSocket>,
_remote_addr: SocketAddr,
) -> Result<DtlsConnection, SecurityError> {
let dtls_config = DtlsConfig {
role: DtlsRole::Client,
version: DtlsVersion::Dtls12,
mtu: 1500,
max_retransmissions: 5,
srtp_profiles: vec![SRTP_AES128_CM_SHA1_80],
};
let mut connection = DtlsConnection::new(dtls_config);
debug!("Generating self-signed certificate for new connection");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => connection.set_certificate(cert),
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to generate certificate: {}",
e
)))
}
}
let transport = match UdpTransport::new(socket.clone(), 1500).await {
Ok(t) => t,
Err(e) => {
return Err(SecurityError::Configuration(format!(
"Failed to create DTLS transport: {}",
e
)))
}
};
let transport_arc = Arc::new(Mutex::new(transport));
let start_result = transport_arc.lock().await.start().await;
if start_result.is_ok() {
debug!("DTLS transport started successfully for new connection");
connection.set_transport(transport_arc.clone());
debug!("Transport set on new connection");
Ok(connection)
} else {
let err = start_result.err().unwrap();
error!("Failed to start DTLS transport for new connection: {}", err);
Err(SecurityError::Configuration(format!(
"Failed to start DTLS transport: {}",
err
)))
}
}
pub fn create_dtls_config(config: &ClientSecurityConfig) -> DtlsConfig {
api_create_dtls_config(config)
}