use std::sync::Arc;
use base64ct::{Base64, Encoding};
use sctp_proto::{ClientConfig, TransportConfig, generate_snap_token};
use super::SctpError as Error;
pub(super) fn webrtc_transport_config() -> Arc<TransportConfig> {
Arc::new(
TransportConfig::default()
.with_max_init_retransmits(None)
.with_max_data_retransmits(None),
)
}
#[derive(Debug, Clone)]
pub struct SctpInitData {
pub(crate) transport: Arc<TransportConfig>,
pub(crate) local_init: Option<Vec<u8>>,
pub(crate) remote_init: Option<Vec<u8>>,
}
impl Default for SctpInitData {
fn default() -> Self {
SctpInitData {
transport: webrtc_transport_config(),
local_init: None,
remote_init: None,
}
}
}
impl SctpInitData {
pub fn new() -> Self {
Self::default()
}
pub fn local_init_chunk(&mut self) -> Result<Vec<u8>, Error> {
if let Some(init) = &self.local_init {
return Ok(init.clone());
}
let init = generate_snap_token(&self.transport)?.to_vec();
self.local_init = Some(init.clone());
Ok(init)
}
pub fn local_init_string(&mut self) -> Result<String, Error> {
self.local_init_chunk().map(|c| b64_encode(&c))
}
pub fn has_remote_init_chunk(&self) -> bool {
self.remote_init.is_some()
}
pub fn remote_init_string(&self) -> Option<String> {
self.remote_init.as_ref().map(|b| b64_encode(b))
}
pub fn set_remote_init_chunk(&mut self, value: Vec<u8>) {
self.remote_init = Some(value);
}
pub fn set_remote_init_string(&mut self, value: &str) -> Result<(), Error> {
let mut buf = vec![0u8; value.len()];
let len = Base64::decode(value, &mut buf)
.map_err(|_| Error::InvalidSnap)?
.len();
buf.truncate(len);
self.set_remote_init_chunk(buf);
Ok(())
}
pub(crate) fn into_client_config(self) -> ClientConfig {
let mut config = ClientConfig::new();
config.transport = self.transport;
match (self.local_init, self.remote_init) {
(Some(local), Some(remote)) => {
config = config.with_snap(local.into(), remote.into());
}
(Some(_), None) | (None, Some(_)) => {
unreachable!("SNAP requires both local and remote INIT chunks");
}
(None, None) => {}
}
config
}
}
pub(super) fn b64_encode(data: &[u8]) -> String {
let mut buf = vec![0u8; Base64::encoded_len(data)];
let encoded = Base64::encode(data, &mut buf).expect("buffer sized correctly");
encoded.to_string()
}