1pub use tokio_rustls::rustls;
8
9use crate::async_carrier::{self, AsyncCommandSender, DemandBatcher};
10use datum::{Flow, Keep, NotUsed, Sink, Source, StreamCompletion, StreamError, StreamResult};
11use std::net::SocketAddr;
12use std::sync::{Arc, Mutex, atomic::AtomicUsize, mpsc as std_mpsc};
13use std::time::Duration;
14use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
15use tokio::net::{TcpListener, TcpStream, ToSocketAddrs};
16use tokio::runtime::Handle;
17use tokio::sync::{mpsc, watch};
18use tokio::task::JoinHandle;
19use tokio_rustls::rustls::pki_types::ServerName;
20use tokio_rustls::{TlsAcceptor, TlsConnector};
21
22const DEFAULT_CHUNK_SIZE: usize = 8192;
23const DEFAULT_RECEIVE_BUFFER: usize = 64;
24const TRANSIENT_ACCEPT_BACKOFF: Duration = Duration::from_millis(10);
25
26static ACTIVE_TLS_CONNECTIONS: AtomicUsize = AtomicUsize::new(0);
27
28#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
30pub struct TlsCarrierDiagnosticCounts {
31 pub transient_accept_errors: u64,
32 pub handshake_failures: u64,
33}
34
35#[derive(Clone, Default)]
37pub struct TlsCarrierDiagnostics {
38 counts: Arc<Mutex<TlsCarrierDiagnosticCounts>>,
39}
40
41impl TlsCarrierDiagnostics {
42 #[must_use]
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 #[must_use]
48 pub fn snapshot(&self) -> TlsCarrierDiagnosticCounts {
49 *self
50 .counts
51 .lock()
52 .unwrap_or_else(|poison| poison.into_inner())
53 }
54
55 fn record_transient_accept_error(&self) {
56 let mut counts = self
57 .counts
58 .lock()
59 .unwrap_or_else(|poison| poison.into_inner());
60 counts.transient_accept_errors = counts.transient_accept_errors.saturating_add(1);
61 }
62
63 fn record_handshake_failure(&self) {
64 let mut counts = self
65 .counts
66 .lock()
67 .unwrap_or_else(|poison| poison.into_inner());
68 counts.handshake_failures = counts.handshake_failures.saturating_add(1);
69 }
70}
71
72pub type TlsByteSource = Source<Vec<u8>, NotUsed>;
79
80pub type TlsByteSink = Sink<Vec<u8>, StreamCompletion<NotUsed>>;
85
86enum DemandResponse<T> {
87 Item(T),
88 Complete,
89 Error(StreamError),
90}
91
92struct ReadResource {
93 receiver: std_mpsc::Receiver<DemandResponse<Vec<u8>>>,
94 carrier: TlsCarrier,
95 demand: DemandBatcher,
96 pending: Option<DemandResponse<Vec<u8>>>,
97}
98
99impl Drop for ReadResource {
100 fn drop(&mut self) {
101 self.carrier.close_read();
102 }
103}
104
105enum TlsCarrierCommand {
106 Demand(usize),
107 SendOne(Vec<u8>),
108 SendBatch(Vec<Vec<u8>>),
109 CloseRead,
110 CloseWrite {
111 ack: std_mpsc::Sender<StreamResult<()>>,
112 },
113}
114
115#[derive(Clone)]
116struct TlsCarrier {
117 inner: Arc<TlsCarrierInner>,
118}
119
120struct TlsCarrierInner {
121 commands: AsyncCommandSender<TlsCarrierCommand>,
122 send_errors: Mutex<std_mpsc::Receiver<StreamError>>,
123 task: Mutex<Option<JoinHandle<()>>>,
124 _execution: async_carrier::ShardedTokioCarrierExecution,
125}
126
127impl Drop for TlsCarrierInner {
128 fn drop(&mut self) {
129 if let Some(task) = self
130 .task
131 .lock()
132 .unwrap_or_else(|poison| poison.into_inner())
133 .take()
134 {
135 task.abort();
136 }
137 }
138}
139
140impl TlsCarrier {
141 fn close_read(&self) {
142 let _ = self.inner.commands.try_send(TlsCarrierCommand::CloseRead);
143 }
144
145 fn request_demand(&self, demand: usize) -> StreamResult<()> {
146 self.inner
147 .commands
148 .send_or_blocking(TlsCarrierCommand::Demand(demand))
149 }
150
151 fn send_items(&self, items: Vec<Vec<u8>>) -> StreamResult<()> {
152 self.check_send_error()?;
153 self.inner
154 .commands
155 .send_or_blocking(TlsCarrierCommand::SendBatch(items))
156 .map_err(|error| StreamError::Failed(format!("TLS send batch failed: {error:?}")))
157 }
158
159 fn send_one(&self, item: Vec<u8>) -> StreamResult<()> {
160 self.check_send_error()?;
161 self.inner
162 .commands
163 .send_or_blocking(TlsCarrierCommand::SendOne(item))
164 .map_err(|error| StreamError::Failed(format!("TLS send failed: {error:?}")))
165 }
166
167 fn close_write(&self) -> StreamResult<()> {
168 self.check_send_error()?;
169 let (ack_sender, ack_receiver) = std_mpsc::channel();
170 if self
171 .inner
172 .commands
173 .send_or_blocking(TlsCarrierCommand::CloseWrite { ack: ack_sender })
174 .is_err()
175 {
176 return Ok(());
177 }
178 match ack_receiver.recv() {
179 Ok(result) => result,
180 Err(_) => Err(abrupt_termination()),
181 }?;
182 self.check_send_error()
183 }
184
185 fn check_send_error(&self) -> StreamResult<()> {
186 match self
187 .inner
188 .send_errors
189 .lock()
190 .expect("TLS carrier send error receiver poisoned")
191 .try_recv()
192 {
193 Ok(error) => Err(error),
194 Err(std_mpsc::TryRecvError::Empty) | Err(std_mpsc::TryRecvError::Disconnected) => {
195 Ok(())
196 }
197 }
198 }
199}
200
201struct SendResource {
202 carrier: TlsCarrier,
203 pending: Vec<Vec<u8>>,
204 batch_size: usize,
205}
206
207struct BindResource {
208 demands: mpsc::Sender<std_mpsc::Sender<DemandResponse<TlsIncomingConnection>>>,
209 cancel: watch::Sender<bool>,
210 task: JoinHandle<()>,
211}
212
213struct TlsBindTask {
214 listener: TcpListener,
215 acceptor: TlsAcceptor,
216 local_addr: SocketAddr,
217 chunk_size: usize,
218 handle: Handle,
219 diagnostics: Option<TlsCarrierDiagnostics>,
220 demands: mpsc::Receiver<std_mpsc::Sender<DemandResponse<TlsIncomingConnection>>>,
221 cancel: watch::Receiver<bool>,
222}
223
224impl Drop for BindResource {
225 fn drop(&mut self) {
226 let _ = self.cancel.send(true);
227 self.task.abort();
228 }
229}
230
231fn io_error(error: std::io::Error) -> StreamError {
232 StreamError::Failed(error.to_string())
233}
234
235fn abrupt_termination() -> StreamError {
236 StreamError::AbruptTermination
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241pub struct TlsConnection {
242 pub local_addr: SocketAddr,
243 pub remote_addr: SocketAddr,
244}
245
246impl TlsConnection {
247 #[must_use]
248 pub fn local_addr(&self) -> SocketAddr {
249 self.local_addr
250 }
251
252 #[must_use]
253 pub fn remote_addr(&self) -> SocketAddr {
254 self.remote_addr
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub struct TlsBinding {
261 pub local_addr: SocketAddr,
262}
263
264impl TlsBinding {
265 #[must_use]
266 pub fn local_addr(&self) -> SocketAddr {
267 self.local_addr
268 }
269}
270
271pub struct TlsIncomingConnection {
273 connection: TlsConnection,
274 source: TlsByteSource,
275 sink: TlsByteSink,
276}
277
278impl TlsIncomingConnection {
279 #[must_use]
280 pub fn local_addr(&self) -> SocketAddr {
281 self.connection.local_addr
282 }
283
284 #[must_use]
285 pub fn remote_addr(&self) -> SocketAddr {
286 self.connection.remote_addr
287 }
288
289 #[must_use]
290 pub fn connection(&self) -> TlsConnection {
291 self.connection
292 }
293
294 #[must_use]
295 pub fn into_parts(self) -> (TlsByteSource, TlsByteSink) {
296 (self.source, self.sink)
297 }
298
299 #[must_use]
300 pub fn into_flow(self) -> Flow<Vec<u8>, Vec<u8>, NotUsed> {
301 Flow::from_sink_and_source_coupled(self.sink, self.source)
302 .map_materialized_value(|_| NotUsed)
303 }
304}
305
306pub struct TokioTls;
308
309pub type Tls = TokioTls;
311
312impl TokioTls {
313 #[must_use]
319 pub fn outgoing_connection<A>(
320 addr: A,
321 server_name: ServerName<'static>,
322 client_config: Arc<rustls::ClientConfig>,
323 chunk_size: usize,
324 ) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<TlsConnection>>
325 where
326 A: ToSocketAddrs + Clone + Send + Sync + 'static,
327 {
328 assert!(chunk_size > 0, "chunk size must be greater than zero");
329 Flow::future_flow(move || {
330 let addr = addr.clone();
331 let server_name = server_name.clone();
332 let client_config = Arc::clone(&client_config);
333 async move {
334 let handle = Handle::current();
335 tls_client_connect(addr, server_name, client_config, handle, chunk_size).await
336 }
337 })
338 }
339
340 #[must_use]
342 pub fn outgoing_connection_default<A>(
343 addr: A,
344 server_name: ServerName<'static>,
345 client_config: Arc<rustls::ClientConfig>,
346 ) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<TlsConnection>>
347 where
348 A: ToSocketAddrs + Clone + Send + Sync + 'static,
349 {
350 Self::outgoing_connection(addr, server_name, client_config, DEFAULT_CHUNK_SIZE)
351 }
352
353 #[must_use]
359 pub fn bind<A>(
360 addr: A,
361 server_config: Arc<rustls::ServerConfig>,
362 chunk_size: usize,
363 ) -> Source<TlsIncomingConnection, StreamCompletion<TlsBinding>>
364 where
365 A: ToSocketAddrs + Clone + Send + Sync + 'static,
366 {
367 Self::bind_optional_diagnostics(addr, server_config, chunk_size, None)
368 }
369
370 #[must_use]
372 pub fn bind_with_diagnostics<A>(
373 addr: A,
374 server_config: Arc<rustls::ServerConfig>,
375 chunk_size: usize,
376 diagnostics: TlsCarrierDiagnostics,
377 ) -> Source<TlsIncomingConnection, StreamCompletion<TlsBinding>>
378 where
379 A: ToSocketAddrs + Clone + Send + Sync + 'static,
380 {
381 Self::bind_optional_diagnostics(addr, server_config, chunk_size, Some(diagnostics))
382 }
383
384 fn bind_optional_diagnostics<A>(
385 addr: A,
386 server_config: Arc<rustls::ServerConfig>,
387 chunk_size: usize,
388 diagnostics: Option<TlsCarrierDiagnostics>,
389 ) -> Source<TlsIncomingConnection, StreamCompletion<TlsBinding>>
390 where
391 A: ToSocketAddrs + Clone + Send + Sync + 'static,
392 {
393 assert!(chunk_size > 0, "chunk size must be greater than zero");
394 Source::lazy_future_source(move || {
395 let addr = addr.clone();
396 let server_config = Arc::clone(&server_config);
397 let diagnostics = diagnostics.clone();
398 async move {
399 let handle = Handle::current();
400 let listener = TcpListener::bind(addr).await.map_err(io_error)?;
401 let local_addr = listener.local_addr().map_err(io_error)?;
402 Ok(tls_bind_source(
403 listener,
404 server_config,
405 local_addr,
406 handle,
407 chunk_size,
408 diagnostics,
409 ))
410 }
411 })
412 }
413
414 #[must_use]
416 pub fn bind_default<A>(
417 addr: A,
418 server_config: Arc<rustls::ServerConfig>,
419 ) -> Source<TlsIncomingConnection, StreamCompletion<TlsBinding>>
420 where
421 A: ToSocketAddrs + Clone + Send + Sync + 'static,
422 {
423 Self::bind(addr, server_config, DEFAULT_CHUNK_SIZE)
424 }
425}
426
427pub(crate) fn tls_flow_from_stream_with_execution<S>(
428 stream: S,
429 connection: TlsConnection,
430 execution: async_carrier::ShardedTokioCarrierExecution,
431 chunk_size: usize,
432) -> Flow<Vec<u8>, Vec<u8>, TlsConnection>
433where
434 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
435{
436 let (source, sink) = single_use_tls_halves(stream, execution, chunk_size);
437 Flow::from_sink_and_source(sink, source).map_materialized_value(move |_| connection)
438}
439
440fn tls_incoming_connection<S>(
441 stream: S,
442 connection: TlsConnection,
443 execution: async_carrier::ShardedTokioCarrierExecution,
444 chunk_size: usize,
445) -> TlsIncomingConnection
446where
447 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
448{
449 let (source, sink) = single_use_tls_halves(stream, execution, chunk_size);
450 TlsIncomingConnection {
451 connection,
452 source,
453 sink,
454 }
455}
456
457fn single_use_tls_halves<S>(
458 stream: S,
459 execution: async_carrier::ShardedTokioCarrierExecution,
460 chunk_size: usize,
461) -> (TlsByteSource, TlsByteSink)
462where
463 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
464{
465 let (carrier, receiver) =
466 start_tls_carrier(stream, execution, chunk_size, DEFAULT_RECEIVE_BUFFER);
467 let source =
468 single_use_tls_source_from_carrier(carrier.clone(), receiver, DEFAULT_RECEIVE_BUFFER);
469 let sink = single_use_tls_sink_from_carrier(carrier, 1);
470 (source, sink)
471}
472
473fn single_use_tls_source_from_carrier(
474 carrier: TlsCarrier,
475 receiver: std_mpsc::Receiver<DemandResponse<Vec<u8>>>,
476 receive_buffer: usize,
477) -> TlsByteSource {
478 let receiver = Arc::new(Mutex::new(Some(receiver)));
479 Source::unfold_resource(
480 {
481 let receiver = Arc::clone(&receiver);
482 move || {
483 let receiver = receiver
484 .lock()
485 .expect("single-use TLS receiver poisoned")
486 .take()
487 .ok_or_else(|| StreamError::Failed("TLS source already materialized".into()))?;
488 let demand = DemandBatcher::new(receive_buffer);
489 let pending = match carrier.request_demand(demand.initial()) {
490 Ok(()) => None,
491 Err(error) => match receiver.try_recv() {
492 Ok(response) => Some(response),
493 Err(std_mpsc::TryRecvError::Empty) => return Err(error),
494 Err(std_mpsc::TryRecvError::Disconnected) => {
495 return Err(abrupt_termination());
496 }
497 },
498 };
499 Ok(ReadResource {
500 receiver,
501 carrier: carrier.clone(),
502 demand,
503 pending,
504 })
505 }
506 },
507 read_next_chunk,
508 close_read_resource,
509 )
510}
511
512fn read_next_chunk(resource: &mut ReadResource) -> StreamResult<Option<Vec<u8>>> {
513 let response = match resource.pending.take() {
514 Some(response) => response,
515 None => resource.receiver.recv().map_err(|_| abrupt_termination())?,
516 };
517 match response {
518 DemandResponse::Item(chunk) => {
519 if let Some(demand) = resource.demand.record_consumed() {
520 let _ = resource.carrier.request_demand(demand);
521 }
522 Ok(Some(chunk))
523 }
524 DemandResponse::Complete => Ok(None),
525 DemandResponse::Error(error) => Err(error),
526 }
527}
528
529fn close_read_resource(resource: ReadResource) -> StreamResult<()> {
530 resource.carrier.close_read();
531 Ok(())
532}
533
534fn start_tls_carrier<S>(
535 stream: S,
536 execution: async_carrier::ShardedTokioCarrierExecution,
537 chunk_size: usize,
538 receive_buffer: usize,
539) -> (TlsCarrier, std_mpsc::Receiver<DemandResponse<Vec<u8>>>)
540where
541 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
542{
543 let command_capacity = async_carrier::DEFAULT_COMMAND_BUFFER.max(receive_buffer);
544 let (commands, command_receiver) = async_carrier::command_channel(command_capacity, "TLS");
545 let (send_error_sender, send_error_receiver) = std_mpsc::channel();
546 let (receive_sender, receive_receiver) =
547 std_mpsc::sync_channel(receive_buffer.saturating_add(1));
548 let (reader, writer) = tokio::io::split(stream);
549 let command_keepalive = commands.clone();
550 let task = execution.handle().spawn(run_tls_carrier_task(
551 reader,
552 writer,
553 chunk_size,
554 receive_sender,
555 send_error_sender,
556 command_keepalive,
557 command_receiver,
558 ));
559 (
560 TlsCarrier {
561 inner: Arc::new(TlsCarrierInner {
562 commands,
563 send_errors: Mutex::new(send_error_receiver),
564 task: Mutex::new(Some(task)),
565 _execution: execution,
566 }),
567 },
568 receive_receiver,
569 )
570}
571
572async fn run_tls_carrier_task<R, W>(
573 mut reader: R,
574 mut writer: W,
575 chunk_size: usize,
576 receive_sender: std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
577 send_error_sender: std_mpsc::Sender<StreamError>,
578 _command_keepalive: AsyncCommandSender<TlsCarrierCommand>,
579 mut commands: mpsc::Receiver<TlsCarrierCommand>,
580) where
581 R: AsyncRead + Unpin + Send + 'static,
582 W: AsyncWrite + Unpin + Send + 'static,
583{
584 let mut buffer = vec![0_u8; chunk_size];
585 let mut pending_tail = Vec::with_capacity(chunk_size);
586 let mut requested = 0_usize;
587 let mut read_open = true;
588 let mut write_open = true;
589
590 loop {
591 if !read_open && !write_open {
592 return;
593 }
594
595 if read_open && requested > 0 {
596 tokio::select! {
597 biased;
598 command = commands.recv() => {
599 let Some(command) = command else {
600 return;
601 };
602 if !handle_tls_carrier_command(
603 &mut writer,
604 command,
605 &send_error_sender,
606 &mut read_open,
607 &mut write_open,
608 &mut requested,
609 ).await {
610 return;
611 }
612 }
613 read = reader.read(&mut buffer) => {
614 match read {
615 Ok(0) => {
616 if !pending_tail.is_empty() {
617 match try_send_tls_read_response(
618 &receive_sender,
619 DemandResponse::Item(std::mem::take(&mut pending_tail)),
620 ) {
621 TlsQueueOutcome::Queued => {
622 requested = requested.saturating_sub(1);
623 }
624 TlsQueueOutcome::Closed => {
625 read_open = false;
626 continue;
627 }
628 TlsQueueOutcome::Full => {
629 report_tls_read_error(
630 &receive_sender,
631 &send_error_sender,
632 tls_receive_buffer_overflow(),
633 );
634 return;
635 }
636 }
637 }
638 match try_send_tls_read_response(
639 &receive_sender,
640 DemandResponse::Complete,
641 ) {
642 TlsQueueOutcome::Queued | TlsQueueOutcome::Closed => {
643 read_open = false;
644 }
645 TlsQueueOutcome::Full => {
646 report_tls_read_error(
647 &receive_sender,
648 &send_error_sender,
649 tls_receive_buffer_overflow(),
650 );
651 return;
652 }
653 }
654 }
655 Ok(read) => {
656 match queue_tls_read_chunks(
657 &receive_sender,
658 &send_error_sender,
659 chunk_size,
660 &mut pending_tail,
661 &buffer[..read],
662 ) {
663 TlsReadQueueResult::Queued(queued) => {
664 requested = requested.saturating_sub(queued);
665 }
666 TlsReadQueueResult::Closed => {
667 read_open = false;
668 }
669 TlsReadQueueResult::Failed => {
670 return;
671 }
672 }
673 }
674 Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {}
675 Err(error) => {
676 report_tls_read_error(
677 &receive_sender,
678 &send_error_sender,
679 io_error(error),
680 );
681 return;
682 }
683 }
684 }
685 }
686 } else {
687 let Some(command) = commands.recv().await else {
688 return;
689 };
690 if !handle_tls_carrier_command(
691 &mut writer,
692 command,
693 &send_error_sender,
694 &mut read_open,
695 &mut write_open,
696 &mut requested,
697 )
698 .await
699 {
700 return;
701 }
702 }
703 }
704}
705
706async fn handle_tls_carrier_command<W>(
707 writer: &mut W,
708 command: TlsCarrierCommand,
709 send_error_sender: &std_mpsc::Sender<StreamError>,
710 read_open: &mut bool,
711 write_open: &mut bool,
712 requested: &mut usize,
713) -> bool
714where
715 W: AsyncWrite + Unpin,
716{
717 match command {
718 TlsCarrierCommand::Demand(demand) => {
719 *requested = requested.saturating_add(demand);
720 true
721 }
722 TlsCarrierCommand::SendOne(chunk) => {
723 if !*write_open {
724 report_tls_write_error(
725 send_error_sender,
726 StreamError::Failed("TLS write side is closed".to_owned()),
727 );
728 return *read_open;
729 }
730 if write_one_tls_chunk(writer, send_error_sender, &chunk).await {
731 true
732 } else {
733 *write_open = false;
734 *read_open
735 }
736 }
737 TlsCarrierCommand::SendBatch(chunks) => {
738 if !*write_open {
739 report_tls_write_error(
740 send_error_sender,
741 StreamError::Failed("TLS write side is closed".to_owned()),
742 );
743 return *read_open;
744 }
745 for chunk in &chunks {
746 if let Err(error) = writer.write_all(chunk).await.map_err(io_error) {
747 report_tls_write_error(send_error_sender, error);
748 *write_open = false;
749 return *read_open;
750 }
751 }
752 if let Err(error) = writer.flush().await.map_err(io_error) {
753 report_tls_write_error(send_error_sender, error);
754 *write_open = false;
755 return *read_open;
756 }
757 true
758 }
759 TlsCarrierCommand::CloseRead => {
760 *read_open = false;
761 true
762 }
763 TlsCarrierCommand::CloseWrite { ack } => {
764 *write_open = false;
765 let result = close_tls_writer(writer).await;
766 match result {
767 Ok(()) => {
768 let _ = ack.send(Ok(()));
769 true
770 }
771 Err(error) => {
772 report_tls_write_error(send_error_sender, error.clone());
773 let _ = ack.send(Err(error));
774 *read_open
775 }
776 }
777 }
778 }
779}
780
781async fn write_one_tls_chunk<W>(
782 writer: &mut W,
783 send_error_sender: &std_mpsc::Sender<StreamError>,
784 chunk: &[u8],
785) -> bool
786where
787 W: AsyncWrite + Unpin,
788{
789 if let Err(error) = writer.write_all(chunk).await.map_err(io_error) {
790 report_tls_write_error(send_error_sender, error);
791 return false;
792 }
793 if let Err(error) = writer.flush().await.map_err(io_error) {
794 report_tls_write_error(send_error_sender, error);
795 return false;
796 }
797 true
798}
799
800async fn close_tls_writer<W>(writer: &mut W) -> StreamResult<()>
801where
802 W: AsyncWrite + Unpin,
803{
804 writer.flush().await.map_err(io_error)?;
805 writer.shutdown().await.map_err(io_error)
806}
807
808enum TlsReadQueueResult {
809 Queued(usize),
810 Closed,
811 Failed,
812}
813
814enum TlsQueueOutcome {
815 Queued,
816 Full,
817 Closed,
818}
819
820fn queue_tls_read_chunks(
821 sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
822 send_error_sender: &std_mpsc::Sender<StreamError>,
823 chunk_size: usize,
824 pending_tail: &mut Vec<u8>,
825 read_buffer: &[u8],
826) -> TlsReadQueueResult {
827 let mut offset = 0;
828 let mut queued = 0_usize;
829 if !pending_tail.is_empty() {
830 let needed = chunk_size - pending_tail.len();
831 let take = needed.min(read_buffer.len());
832 pending_tail.extend_from_slice(&read_buffer[..take]);
833 offset += take;
834 if pending_tail.len() == chunk_size {
835 match try_send_tls_read_response(
836 sender,
837 DemandResponse::Item(std::mem::take(pending_tail)),
838 ) {
839 TlsQueueOutcome::Queued => queued += 1,
840 TlsQueueOutcome::Closed => return TlsReadQueueResult::Closed,
841 TlsQueueOutcome::Full => {
842 report_tls_read_error(sender, send_error_sender, tls_receive_buffer_overflow());
843 return TlsReadQueueResult::Failed;
844 }
845 }
846 }
847 }
848
849 while offset + chunk_size <= read_buffer.len() {
850 let next = offset + chunk_size;
851 match try_send_tls_read_response(
852 sender,
853 DemandResponse::Item(read_buffer[offset..next].to_vec()),
854 ) {
855 TlsQueueOutcome::Queued => queued += 1,
856 TlsQueueOutcome::Closed => return TlsReadQueueResult::Closed,
857 TlsQueueOutcome::Full => {
858 report_tls_read_error(sender, send_error_sender, tls_receive_buffer_overflow());
859 return TlsReadQueueResult::Failed;
860 }
861 }
862 offset = next;
863 }
864
865 if offset < read_buffer.len() {
866 pending_tail.extend_from_slice(&read_buffer[offset..]);
867 }
868 TlsReadQueueResult::Queued(queued)
869}
870
871fn try_send_tls_read_response(
872 sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
873 item: DemandResponse<Vec<u8>>,
874) -> TlsQueueOutcome {
875 match sender.try_send(item) {
876 Ok(()) => TlsQueueOutcome::Queued,
877 Err(std_mpsc::TrySendError::Full(_)) => TlsQueueOutcome::Full,
878 Err(std_mpsc::TrySendError::Disconnected(_)) => TlsQueueOutcome::Closed,
879 }
880}
881
882fn report_tls_read_error(
883 receive_sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
884 send_error_sender: &std_mpsc::Sender<StreamError>,
885 error: StreamError,
886) {
887 let _ = send_error_sender.send(error.clone());
888 let _ = receive_sender.try_send(DemandResponse::Error(error));
889}
890
891fn report_tls_write_error(send_error_sender: &std_mpsc::Sender<StreamError>, error: StreamError) {
892 let _ = send_error_sender.send(error);
893}
894
895fn tls_receive_buffer_overflow() -> StreamError {
896 StreamError::Failed("TLS receive buffer filled without downstream demand".to_owned())
897}
898
899fn single_use_tls_sink_from_carrier(carrier: TlsCarrier, batch_size: usize) -> TlsByteSink {
900 let carrier = Arc::new(Mutex::new(Some(carrier)));
901 Flow::<Vec<u8>, Vec<u8>>::identity()
902 .map_with_resource(
903 {
904 let carrier = Arc::clone(&carrier);
905 move || {
906 let carrier = carrier
907 .lock()
908 .expect("single-use TLS carrier poisoned")
909 .take()
910 .ok_or_else(|| {
911 StreamError::Failed("TLS sink already materialized".into())
912 })?;
913 Ok(SendResource {
914 carrier,
915 pending: Vec::with_capacity(batch_size),
916 batch_size,
917 })
918 }
919 },
920 |resource, chunk| {
921 send_tls_chunk(resource, chunk)?;
922 Ok(NotUsed)
923 },
924 close_tls_send_resource,
925 )
926 .to_mat(Sink::ignore(), Keep::right)
927}
928
929fn close_tls_send_resource(mut resource: SendResource) -> StreamResult<Option<NotUsed>> {
930 flush_tls_send_resource(&mut resource)?;
931 resource.carrier.close_write()?;
932 Ok(None)
933}
934
935fn send_tls_chunk(resource: &mut SendResource, chunk: Vec<u8>) -> StreamResult<()> {
936 if resource.batch_size <= 1 {
937 return resource.carrier.send_one(chunk);
938 }
939 resource.pending.push(chunk);
940 if resource.pending.len() >= resource.batch_size {
941 flush_tls_send_resource(resource)?;
942 }
943 Ok(())
944}
945
946fn flush_tls_send_resource(resource: &mut SendResource) -> StreamResult<()> {
947 if resource.pending.is_empty() {
948 return resource.carrier.check_send_error();
949 }
950 let pending = std::mem::take(&mut resource.pending);
951 resource.carrier.send_items(pending)
952}
953
954fn tls_bind_source(
955 listener: TcpListener,
956 server_config: Arc<rustls::ServerConfig>,
957 local_addr: SocketAddr,
958 handle: Handle,
959 chunk_size: usize,
960 diagnostics: Option<TlsCarrierDiagnostics>,
961) -> Source<TlsIncomingConnection, TlsBinding> {
962 let listener = Arc::new(Mutex::new(Some(listener)));
963 Source::unfold_resource(
964 {
965 let listener = Arc::clone(&listener);
966 let handle = handle.clone();
967 move || {
968 let listener = listener
969 .lock()
970 .expect("single-use TLS listener poisoned")
971 .take()
972 .ok_or_else(|| {
973 StreamError::Failed("TLS listener already materialized".into())
974 })?;
975 let (demand_sender, demand_receiver) = mpsc::channel(1);
976 let (cancel_sender, cancel_receiver) = watch::channel(false);
977 let task = handle.spawn(run_tls_bind_task(TlsBindTask {
978 listener,
979 acceptor: TlsAcceptor::from(Arc::clone(&server_config)),
980 local_addr,
981 chunk_size,
982 handle: handle.clone(),
983 diagnostics: diagnostics.clone(),
984 demands: demand_receiver,
985 cancel: cancel_receiver,
986 }));
987 Ok(BindResource {
988 demands: demand_sender,
989 cancel: cancel_sender,
990 task,
991 })
992 }
993 },
994 |resource| {
995 let (reply_sender, reply_receiver) = std_mpsc::channel();
996 resource
997 .demands
998 .blocking_send(reply_sender)
999 .map_err(|_| abrupt_termination())?;
1000 match reply_receiver.recv() {
1001 Ok(DemandResponse::Item(connection)) => Ok(Some(connection)),
1002 Ok(DemandResponse::Complete) => Ok(None),
1003 Ok(DemandResponse::Error(error)) => Err(error),
1004 Err(_) => Err(abrupt_termination()),
1005 }
1006 },
1007 close_bind_resource,
1008 )
1009 .map_materialized_value(move |_| TlsBinding { local_addr })
1010}
1011
1012fn close_bind_resource(resource: BindResource) -> StreamResult<()> {
1013 let _ = resource.cancel.send(true);
1014 resource.task.abort();
1015 Ok(())
1016}
1017
1018async fn run_tls_bind_task(task: TlsBindTask) {
1019 let TlsBindTask {
1020 listener,
1021 acceptor,
1022 local_addr,
1023 chunk_size,
1024 handle,
1025 diagnostics,
1026 mut demands,
1027 mut cancel,
1028 } = task;
1029 loop {
1030 let reply = tokio::select! {
1031 demand = demands.recv() => match demand {
1032 Some(reply) => reply,
1033 None => return,
1034 },
1035 changed = cancel.changed() => {
1036 let _ = changed;
1037 return;
1038 }
1039 };
1040
1041 loop {
1042 let (tcp, remote_addr) = loop {
1043 let accepted = tokio::select! {
1044 accepted = listener.accept() => accepted,
1045 changed = cancel.changed() => {
1046 let _ = changed;
1047 return;
1048 }
1049 };
1050
1051 match accepted {
1052 Ok(accepted) => break accepted,
1053 Err(error) => match classify_accept_error(&error) {
1054 AcceptErrorDecision::Retry => {
1055 if let Some(diagnostics) = &diagnostics {
1056 diagnostics.record_transient_accept_error();
1057 }
1058 tracing::warn!(
1059 local_addr = %local_addr,
1060 error = %error,
1061 "transient TLS accept error; continuing listener"
1062 );
1063 continue;
1064 }
1065 AcceptErrorDecision::Backoff(delay) => {
1066 if let Some(diagnostics) = &diagnostics {
1067 diagnostics.record_transient_accept_error();
1068 }
1069 tracing::warn!(
1070 local_addr = %local_addr,
1071 error = %error,
1072 backoff_ms = delay.as_millis(),
1073 "resource-pressure TLS accept error; backing off"
1074 );
1075 tokio::select! {
1076 _ = tokio::time::sleep(delay) => {},
1077 changed = cancel.changed() => {
1078 let _ = changed;
1079 return;
1080 }
1081 }
1082 continue;
1083 }
1084 AcceptErrorDecision::Fatal => {
1085 let _ = reply.send(DemandResponse::Error(io_error(error)));
1086 return;
1087 }
1088 },
1089 }
1090 };
1091
1092 let connection = TlsConnection {
1093 local_addr: tcp.local_addr().unwrap_or(local_addr),
1094 remote_addr,
1095 };
1096 let execution = tls_connection_execution(handle.clone());
1097 let accepted = tokio::select! {
1098 accepted = accept_tls_on_execution(tcp, acceptor.clone(), &execution) => accepted,
1099 changed = cancel.changed() => {
1100 let _ = changed;
1101 return;
1102 }
1103 };
1104
1105 match accepted {
1106 Ok(stream) => {
1107 let incoming =
1108 tls_incoming_connection(stream, connection, execution, chunk_size);
1109 if reply.send(DemandResponse::Item(incoming)).is_err() {
1110 return;
1111 }
1112 break;
1113 }
1114 Err(error) => {
1115 if let Some(diagnostics) = &diagnostics {
1116 diagnostics.record_handshake_failure();
1117 }
1118 tracing::warn!(
1119 local_addr = %local_addr,
1120 remote_addr = %remote_addr,
1121 error = ?error,
1122 "TLS server handshake failed; continuing listener"
1123 );
1124 continue;
1125 }
1126 };
1127 }
1128 }
1129}
1130
1131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1132enum AcceptErrorDecision {
1133 Retry,
1134 Backoff(Duration),
1135 Fatal,
1136}
1137
1138fn classify_accept_error(error: &std::io::Error) -> AcceptErrorDecision {
1139 if matches!(
1140 error.kind(),
1141 std::io::ErrorKind::Interrupted
1142 | std::io::ErrorKind::ConnectionAborted
1143 | std::io::ErrorKind::ConnectionReset
1144 ) || error.raw_os_error().is_some_and(is_retry_accept_errno)
1145 {
1146 return AcceptErrorDecision::Retry;
1147 }
1148 if error
1149 .raw_os_error()
1150 .is_some_and(is_resource_pressure_accept_errno)
1151 {
1152 return AcceptErrorDecision::Backoff(TRANSIENT_ACCEPT_BACKOFF);
1153 }
1154 AcceptErrorDecision::Fatal
1155}
1156
1157#[cfg(target_os = "linux")]
1158fn is_retry_accept_errno(code: i32) -> bool {
1159 matches!(code, 4 | 103 | 104)
1160}
1161
1162#[cfg(not(target_os = "linux"))]
1163fn is_retry_accept_errno(_code: i32) -> bool {
1164 false
1165}
1166
1167#[cfg(target_os = "linux")]
1168fn is_resource_pressure_accept_errno(code: i32) -> bool {
1169 matches!(code, 12 | 23 | 24 | 105)
1170}
1171
1172#[cfg(not(target_os = "linux"))]
1173fn is_resource_pressure_accept_errno(_code: i32) -> bool {
1174 false
1175}
1176
1177pub(crate) fn tls_connection_execution(
1178 fallback: Handle,
1179) -> async_carrier::ShardedTokioCarrierExecution {
1180 async_carrier::sharded_tokio_carrier_execution(fallback, &ACTIVE_TLS_CONNECTIONS)
1181}
1182
1183pub(crate) async fn tls_client_connect<A>(
1184 addr: A,
1185 server_name: ServerName<'static>,
1186 client_config: Arc<rustls::ClientConfig>,
1187 fallback: Handle,
1188 chunk_size: usize,
1189) -> StreamResult<Flow<Vec<u8>, Vec<u8>, TlsConnection>>
1190where
1191 A: ToSocketAddrs + Send + 'static,
1192{
1193 let execution = tls_connection_execution(fallback);
1194 let (tls, connection) = execution
1195 .run(async move {
1196 let tcp = TcpStream::connect(addr).await.map_err(io_error)?;
1197 let connection = TlsConnection {
1198 local_addr: tcp.local_addr().map_err(io_error)?,
1199 remote_addr: tcp.peer_addr().map_err(io_error)?,
1200 };
1201 let tls = TlsConnector::from(client_config)
1202 .connect(server_name, tcp)
1203 .await
1204 .map_err(io_error)?;
1205 Ok((tls, connection))
1206 })
1207 .await?;
1208 Ok(tls_flow_from_stream_with_execution(
1209 tls, connection, execution, chunk_size,
1210 ))
1211}
1212
1213async fn accept_tls_on_execution(
1214 tcp: TcpStream,
1215 acceptor: TlsAcceptor,
1216 execution: &async_carrier::ShardedTokioCarrierExecution,
1217) -> StreamResult<tokio_rustls::server::TlsStream<TcpStream>> {
1218 enum AcceptedTcp {
1219 Tokio(TcpStream),
1220 Std(std::net::TcpStream),
1221 }
1222
1223 let tcp = if execution.is_sharded() {
1224 AcceptedTcp::Std(tcp.into_std().map_err(io_error)?)
1225 } else {
1226 AcceptedTcp::Tokio(tcp)
1227 };
1228 execution
1229 .run(async move {
1230 let tcp = match tcp {
1231 AcceptedTcp::Std(std_tcp) => TcpStream::from_std(std_tcp).map_err(io_error)?,
1232 AcceptedTcp::Tokio(tcp) => tcp,
1233 };
1234 acceptor.accept(tcp).await.map_err(io_error)
1235 })
1236 .await
1237}
1238
1239#[cfg(test)]
1240mod tests {
1241 use super::*;
1242
1243 #[test]
1244 fn accept_error_classifier_retries_interrupt_and_peer_abort() {
1245 for kind in [
1246 std::io::ErrorKind::Interrupted,
1247 std::io::ErrorKind::ConnectionAborted,
1248 std::io::ErrorKind::ConnectionReset,
1249 ] {
1250 let error = std::io::Error::from(kind);
1251 assert_eq!(classify_accept_error(&error), AcceptErrorDecision::Retry);
1252 }
1253 }
1254
1255 #[test]
1256 fn accept_error_classifier_rejects_fatal_errors() {
1257 let error = std::io::Error::from(std::io::ErrorKind::AddrInUse);
1258 assert_eq!(classify_accept_error(&error), AcceptErrorDecision::Fatal);
1259 }
1260
1261 #[cfg(target_os = "linux")]
1262 #[test]
1263 fn accept_error_classifier_backs_off_resource_pressure() {
1264 for errno in [12, 23, 24, 105] {
1265 let error = std::io::Error::from_raw_os_error(errno);
1266 assert_eq!(
1267 classify_accept_error(&error),
1268 AcceptErrorDecision::Backoff(TRANSIENT_ACCEPT_BACKOFF),
1269 "errno {errno}"
1270 );
1271 }
1272 }
1273}