use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use core::ops::Range;
use std::sync::MutexGuard;
use super::kernel::KernelConnection;
use super::receive::{Discard, JoinOutput};
use super::{
Connection, ConnectionOutputs, DataKind, Encrypter, MessageIter, MessageIterMode, ReceivePath,
SendOutput, SendPath, SideData, Tcp, TlsInputBuffer,
};
use crate::client::ClientSide;
use crate::common_state::UnborrowedPayload;
use crate::crypto::cipher::OutboundPlain;
use crate::enums::ProtocolVersion;
use crate::error::{AlertDescription, ApiMisuse, Error};
use crate::lock::Mutex;
use crate::msgs::{AlertLevel, Delocator, Message};
use crate::suites::ExtractedSecrets;
use crate::sync::Arc;
use crate::tls13::key_schedule::KeyScheduleTrafficSend;
#[expect(clippy::exhaustive_structs)]
#[derive(Debug)]
pub struct SplitConnection<Side: SideData> {
pub send: SendTraffic,
pub receive: ReceiveTraffic<Side>,
pub outputs: ConnectionOutputs,
pub side_outputs: Side,
}
impl<Side: SideData> SplitConnection<Side> {
pub fn dangerous_into_kernel_connection(
self,
) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
let Self {
send,
receive,
outputs,
side_outputs: _,
} = self;
drop(send);
let ReceiveTraffic {
state, recv, send, ..
} = receive;
let send = Arc::into_inner(send)
.unwrap()
.into_inner()
.unwrap();
if send.pending_send_data() {
return Err(ApiMisuse::KernelConnectionWithPendingSendData.into());
}
Connection::<Side, Tcp>::from_parts_into_kernel_connection(send.send, recv, outputs, state)
}
}
impl<Side: SideData> TryFrom<Connection<Side, Tcp>> for SplitConnection<Side> {
type Error = Error;
fn try_from(conn: Connection<Side, Tcp>) -> Result<Self, Error> {
if conn.is_handshaking() {
return Err(ApiMisuse::SplitDuringHandshake.into());
}
let send = Arc::new(Mutex::new(SendInner {
send: conn.common.send,
aside_buffer: Vec::new(),
}));
let state = conn.state?;
Ok(Self {
send: SendTraffic(send.clone()),
receive: ReceiveTraffic {
state,
recv: conn.common.recv,
send,
pending_flush_sender: false,
},
outputs: conn.common.outputs,
side_outputs: conn.side,
})
}
}
pub struct SendTraffic(pub(super) Arc<Mutex<SendInner>>);
impl SendTraffic {
pub fn write(
&mut self,
application_data: OutboundPlain<'_>,
tls: &mut Vec<u8>,
) -> Result<(), Error> {
let mut inner = self.0.lock().unwrap();
inner.pump(tls);
inner
.send
.send_appdata_encrypt(DataKind::Traffic(application_data), tls)
.map(|_| ())
}
pub fn close(self, tls: &mut Vec<u8>) -> Result<(), Error> {
let mut inner = self.0.lock().unwrap();
inner.pump(tls);
inner.send.send_close_notify(tls)
}
pub fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
let mut inner = self.0.lock().unwrap();
inner.pump(tls);
inner.send.refresh_traffic_keys(tls)
}
}
impl fmt::Debug for SendTraffic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SendTraffic")
.finish_non_exhaustive()
}
}
pub(super) struct SendInner {
send: SendPath,
aside_buffer: Vec<u8>,
}
impl SendInner {
fn pump(&mut self, tls: &mut Vec<u8>) {
tls.extend_from_slice(&self.aside_buffer);
self.aside_buffer.clear();
}
fn pending_send_data(&self) -> bool {
!self.aside_buffer.is_empty() || self.send.has_queued_key_update()
}
fn send_alert(&mut self, level: AlertLevel, desc: AlertDescription) -> Result<(), Error> {
self.send
.send_alert(level, desc, &mut self.aside_buffer)
}
fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) -> Result<(), Error> {
self.send
.send_msg(m, must_encrypt, &mut self.aside_buffer)
}
}
pub struct ReceiveTraffic<Side: SideData> {
pub(crate) state: Side::State,
pub(crate) recv: ReceivePath,
pub(super) send: Arc<Mutex<SendInner>>,
pub(crate) pending_flush_sender: bool,
}
impl<Side: SideData> ReceiveTraffic<Side> {
pub fn read<'a>(
self,
input: &'a mut impl TlsInputBuffer,
) -> Result<ReceiveTrafficState<'a, Side>, Error> {
let Self {
state,
mut recv,
send,
mut pending_flush_sender,
} = self;
let mut tls_unused = Vec::new();
let mut send_adapter = SendAdapter::Unlocked(&send);
let mut state = Ok(state);
let output = JoinOutput {
outputs: &mut Discard,
quic: None,
send: &mut send_adapter,
side: &mut Discard,
};
let mut iter = MessageIter::<Side, _>::receive(
input,
&mut tls_unused,
&mut state,
&mut recv,
output,
MessageIterMode::All,
);
let received_plain = match iter.next(false) {
Some(Ok(payload)) => Some(payload),
Some(Err(error)) => return Err(error),
None => None,
};
debug_assert!(tls_unused.is_empty());
let state = state.unwrap();
if let Some(unborrowed) = received_plain {
let pending_discard = recv.deframer.take_discard();
let UnborrowedPayload::Unborrowed(range) = unborrowed else {
return Err(Error::Unreachable("decrypted data should be borrowed"));
};
if let SendAdapter::Locked { send_required, .. } = send_adapter {
pending_flush_sender |= send_required;
}
drop(send_adapter);
return Ok(ReceiveTrafficState::Available(ReceivedApplicationData {
range,
input,
pending_discard,
rt: Self {
state,
recv,
send,
pending_flush_sender,
},
}));
}
input.discard(recv.deframer.take_discard());
if let SendAdapter::Locked { send_required, .. } = send_adapter {
pending_flush_sender |= send_required;
}
drop(send_adapter);
let mut rt = Self {
state,
recv,
send,
pending_flush_sender,
};
if core::mem::take(&mut rt.pending_flush_sender) {
return Ok(ReceiveTrafficState::FlushSender(FlushSender { rt }));
}
Ok(match rt.recv.has_received_close_notify {
true => ReceiveTrafficState::CloseNotify,
false => ReceiveTrafficState::ReadMore(rt),
})
}
}
impl ReceiveTraffic<ClientSide> {
pub fn tls13_tickets_received(&self) -> u32 {
self.recv.tls13_tickets_received
}
}
impl<Side: SideData> fmt::Debug for ReceiveTraffic<Side> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReceiveTraffic")
.finish_non_exhaustive()
}
}
#[expect(clippy::exhaustive_enums)]
pub enum ReceiveTrafficState<'a, Side: SideData> {
ReadMore(ReceiveTraffic<Side>),
FlushSender(FlushSender<Side>),
Available(ReceivedApplicationData<'a, Side>),
CloseNotify,
}
impl<Side: SideData> fmt::Debug for ReceiveTrafficState<'_, Side> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ReadMore(_) => f
.debug_tuple("ReadMore")
.finish_non_exhaustive(),
Self::FlushSender(_) => f
.debug_tuple("FlushSender")
.finish_non_exhaustive(),
Self::Available(_) => f
.debug_tuple("Available")
.finish_non_exhaustive(),
Self::CloseNotify => write!(f, "CloseNotify"),
}
}
}
pub struct ReceivedApplicationData<'a, Side: SideData> {
input: &'a mut dyn TlsInputBuffer,
range: Range<usize>,
pending_discard: usize,
rt: ReceiveTraffic<Side>,
}
impl<Side: SideData> ReceivedApplicationData<'_, Side> {
pub fn data(&mut self) -> &[u8] {
Delocator::new(self.input.slice_mut()).slice_from_range(&self.range)
}
pub fn into_next(mut self) -> ReceiveTrafficState<'static, Side> {
self.input.discard(self.pending_discard);
if core::mem::take(&mut self.rt.pending_flush_sender) {
return ReceiveTrafficState::FlushSender(FlushSender { rt: self.rt });
}
match self.rt.recv.has_received_close_notify {
true => ReceiveTrafficState::CloseNotify,
false => ReceiveTrafficState::ReadMore(self.rt),
}
}
}
pub struct FlushSender<Side: SideData> {
rt: ReceiveTraffic<Side>,
}
impl<Side: SideData> FlushSender<Side> {
pub fn into_next(self) -> ReceiveTrafficState<'static, Side> {
match self.rt.recv.has_received_close_notify {
true => ReceiveTrafficState::CloseNotify,
false => ReceiveTrafficState::ReadMore(self.rt),
}
}
}
pub(super) enum SendAdapter<'a> {
Unlocked(&'a Mutex<SendInner>),
Locked {
guard: MutexGuard<'a, SendInner>,
send_required: bool,
},
}
impl<'a> SendAdapter<'a> {
fn as_locked<'b>(&'b mut self, may_send: bool) -> &'b mut MutexGuard<'a, SendInner> {
if let Self::Unlocked(m) = self {
*self = Self::Locked {
guard: m.lock().unwrap(),
send_required: false,
};
}
let Self::Locked {
guard,
send_required,
} = self
else {
unreachable!();
};
*send_required |= may_send;
guard
}
}
impl SendOutput for SendAdapter<'_> {
fn negotiated_version(&mut self, version: ProtocolVersion) {
self.as_locked(false)
.send
.negotiated_version(version);
}
fn queue_requested_key_update(&mut self) -> Result<(), Error> {
self.as_locked(true)
.send
.queue_requested_key_update()
}
fn note_key_update_response(&mut self) {
self.as_locked(false)
.send
.note_key_update_response();
}
fn set_encrypter(&mut self, encrypter: Encrypter) {
self.as_locked(false)
.send
.set_encrypter(encrypter);
}
fn update_key_schedule(&mut self, schedule: Box<KeyScheduleTrafficSend>) {
self.as_locked(false)
.send
.update_key_schedule(schedule);
}
fn send_alert(
&mut self,
level: AlertLevel,
desc: AlertDescription,
_wrong_thread_tls: &mut Vec<u8>,
) -> Result<(), Error> {
self.as_locked(true)
.send_alert(level, desc)
}
fn start_traffic(&mut self) {
self.as_locked(false)
.send
.start_traffic();
}
fn send_msg(
&mut self,
m: Message<'_>,
must_encrypt: bool,
_wrong_thread_tls: &mut Vec<u8>,
) -> Result<(), Error> {
self.as_locked(true)
.send_msg(m, must_encrypt)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::crypto::test_provider::Tls13Cipher;
#[test]
fn send_adapter_flag() {
let mut tls = Vec::new();
assert!(!send_flag_for(
|adapter| adapter.negotiated_version(ProtocolVersion::TLSv1_3)
));
assert!(send_flag_for(|adapter| adapter
.queue_requested_key_update()
.unwrap()));
assert!(!send_flag_for(|adapter| adapter.note_key_update_response()));
assert!(!send_flag_for(|adapter| adapter.set_encrypter(Encrypter {
encrypter: Box::new(Tls13Cipher),
limit: 1234,
})));
assert!(send_flag_for(|adapter| adapter
.send_alert(
AlertLevel::Fatal,
AlertDescription::CertificateUnknown,
&mut tls,
)
.unwrap()));
assert!(!send_flag_for(|adapter| adapter.start_traffic()));
assert!(send_flag_for(|adapter| adapter
.send_msg(Message::build_key_update_notify(), false, &mut tls,)
.unwrap()));
}
#[test]
fn pending_send_data() {
let mut send = SendPath::default();
send.set_encrypter(Encrypter {
encrypter: Box::new(Tls13Cipher),
limit: 1234,
});
send.may_send_application_data = true;
let mut inner = SendInner {
send,
aside_buffer: Vec::new(),
};
assert!(!inner.pending_send_data());
inner
.send_alert(AlertLevel::Fatal, AlertDescription::DecodeError)
.unwrap();
assert!(inner.pending_send_data());
let mut tls = Vec::new();
inner.pump(&mut tls);
assert!(!tls.is_empty());
assert!(!inner.pending_send_data());
assert_eq!(
inner
.send
.queue_requested_key_update()
.unwrap_err(),
Error::EncryptError
);
assert!(!inner.pending_send_data());
tls.clear();
assert_eq!(
inner
.send
.send_appdata_encrypt(DataKind::Traffic(b"x".as_slice().into()), &mut tls)
.unwrap_err(),
Error::ApiMisuse(ApiMisuse::WriteAfterSendPathClosed)
);
assert!(tls.is_empty());
assert!(!inner.pending_send_data());
}
fn send_flag_for(f: impl FnOnce(&mut SendAdapter<'_>)) -> bool {
let mut send = SendPath::default();
send.set_encrypter(Encrypter {
encrypter: Box::new(Tls13Cipher),
limit: 1234,
});
let send = Mutex::new(SendInner {
send,
aside_buffer: Vec::new(),
});
let mut adapter = SendAdapter::Unlocked(&send);
f(&mut adapter);
let SendAdapter::Locked { send_required, .. } = adapter else {
panic!("expected to find SendAdapter::Locked");
};
send_required
}
}