1use std::{
10 cell::RefCell,
11 io::{ErrorKind, Read, Write},
12 net::SocketAddr,
13 rc::Rc,
14 time::Instant,
15};
16
17use mio::{Token, net::TcpStream};
18use rustls::{Error as RustlsError, ServerConnection};
19use rusty_ulid::Ulid;
20use sozu_command::{
21 config::MAX_LOOP_ITERATIONS,
22 logging::{LogContext, ansi_palette},
23};
24
25use crate::metrics::names;
26use crate::{
27 Readiness, Ready, SessionMetrics, SessionResult, StateResult, protocol::SessionState,
28 socket::ShortReadProbe, timer::TimeoutContainer,
29};
30
31macro_rules! log_context {
39 ($self:expr) => {{
40 let (open, reset, grey, gray, white) = ansi_palette();
41 format!(
42 "{gray}{ctx}{reset}\t{open}RUSTLS{reset}\t{grey}Session{reset}({gray}sni_bytes{reset}={white}{sni_bytes:?}{reset}, {gray}alpn_bytes{reset}={white}{alpn_bytes:?}{reset}, {gray}version{reset}={white}{version:?}{reset}, {gray}source{reset}={white}{source:?}{reset}, {gray}frontend{reset}={white}{frontend}{reset}, {gray}readiness{reset}={white}{readiness}{reset})\t >>>",
43 open = open,
44 reset = reset,
45 grey = grey,
46 gray = gray,
47 white = white,
48 ctx = $self.log_context(),
49 sni_bytes = $self.session.server_name().map(str::len),
50 alpn_bytes = $self.session.alpn_protocol().map(|bytes| bytes.len()),
51 version = $self.session.protocol_version(),
52 source = $self
53 .peer_address
54 .map(|addr| addr.to_string())
55 .unwrap_or_else(|| "<none>".to_string()),
56 frontend = $self.frontend_token.0,
57 readiness = $self.frontend_readiness,
58 )
59 }};
60}
61
62#[derive(Debug)]
65enum HandshakeReadFault {
66 Closed,
68 ReadTls(std::io::Error),
71 ProcessPackets(RustlsError),
73}
74
75fn handshake_read<R: Read>(
132 session: &mut ServerConnection,
133 stream: &mut R,
134 event: &mut Ready,
135) -> Result<(), HandshakeReadFault> {
136 let mut can_read = true;
137 while can_read && session.wants_read() {
138 let mut probe = ShortReadProbe::new(&mut *stream);
139 let read = loop {
140 match session.read_tls(&mut probe) {
141 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
142 read => break read,
143 }
144 };
145 match read {
146 Ok(0) => return Err(HandshakeReadFault::Closed),
147 Ok(_) => {
148 if probe.was_short() {
149 event.remove(Ready::READABLE);
150 can_read = false;
151 }
152 }
153 Err(e) if e.kind() == ErrorKind::WouldBlock => {
154 event.remove(Ready::READABLE);
155 can_read = false;
156 }
157 Err(e) => {
158 if matches!(
161 e.kind(),
162 ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted
163 ) {
164 incr!(names::rustls::READ_RESET);
165 }
166 return Err(HandshakeReadFault::ReadTls(e));
167 }
168 }
169 session
170 .process_new_packets()
171 .map_err(HandshakeReadFault::ProcessPackets)?;
172 }
173 debug_assert!(
176 can_read || !event.is_readable(),
177 "the handshake stopped reading on an empty queue but kept READABLE"
178 );
179 Ok(())
180}
181
182fn handshake_write<W: Write>(
190 session: &mut ServerConnection,
191 stream: &mut W,
192) -> std::io::Result<usize> {
193 loop {
194 match session.write_tls(stream) {
195 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
196 written => break written,
197 }
198 }
199}
200
201pub enum TlsState {
202 Initial,
203 Handshake,
204 Established,
205 Error,
206}
207
208pub struct TlsHandshake {
209 pub container_frontend_timeout: TimeoutContainer,
210 pub frontend_readiness: Readiness,
211 frontend_token: Token,
212 pub peer_address: Option<SocketAddr>,
213 pub request_id: Ulid,
214 pub session: ServerConnection,
215 pub stream: TcpStream,
216 handshake_started_at: Option<Instant>,
221}
222
223impl TlsHandshake {
224 pub fn new(
231 container_frontend_timeout: TimeoutContainer,
232 session: ServerConnection,
233 stream: TcpStream,
234 frontend_token: Token,
235 request_id: Ulid,
236 peer_address: Option<SocketAddr>,
237 ) -> TlsHandshake {
238 TlsHandshake {
239 container_frontend_timeout,
240 frontend_readiness: Readiness {
241 interest: Ready::READABLE | Ready::HUP | Ready::ERROR,
242 event: Ready::EMPTY,
243 },
244 frontend_token,
245 peer_address,
246 request_id,
247 session,
248 stream,
249 handshake_started_at: None,
250 }
251 }
252
253 fn record_handshake_duration_ms(&mut self) -> Option<u128> {
259 let was_anchored = self.handshake_started_at.is_some();
260 let elapsed = self
261 .handshake_started_at
262 .take()
263 .map(|t| t.elapsed().as_millis());
264 debug_assert!(
268 self.handshake_started_at.is_none(),
269 "handshake anchor must be cleared after recording the duration"
270 );
271 debug_assert_eq!(
272 elapsed.is_some(),
273 was_anchored,
274 "a duration is returned iff the handshake had been anchored"
275 );
276 elapsed
277 }
278
279 pub fn readable(&mut self) -> SessionResult {
280 self.handshake_started_at.get_or_insert_with(Instant::now);
285 debug_assert!(
287 self.handshake_started_at.is_some(),
288 "handshake anchor must be set before driving TLS I/O"
289 );
290
291 let was_handshaking = self.session.is_handshaking();
295
296 match handshake_read(
297 &mut self.session,
298 &mut self.stream,
299 &mut self.frontend_readiness.event,
300 ) {
301 Ok(()) => {}
302 Err(HandshakeReadFault::Closed) => {
305 debug!("{} Connection closed during handshake", log_context!(self));
306 return SessionResult::Close;
307 }
308 Err(HandshakeReadFault::ReadTls(e))
309 if matches!(
310 e.kind(),
311 ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted
312 ) =>
313 {
314 debug!(
315 "{} Connection reset during handshake: {:?}",
316 log_context!(self),
317 e
318 );
319 return SessionResult::Close;
320 }
321 Err(HandshakeReadFault::ReadTls(e)) => {
322 error!(
323 "{} Could not perform handshake: {:?}",
324 log_context!(self),
325 e
326 );
327 return SessionResult::Close;
328 }
329 Err(HandshakeReadFault::ProcessPackets(e)) => {
330 self.log_handshake_error(&e);
331 return SessionResult::Close;
332 }
333 }
334
335 debug_assert!(
338 was_handshaking || !self.session.is_handshaking(),
339 "rustls handshake must not regress from finished back to handshaking"
340 );
341
342 if self.frontend_readiness.event.is_hup() && self.session.is_handshaking() {
348 debug!(
349 "{} Connection closed before the handshake completed",
350 log_context!(self)
351 );
352 return SessionResult::Close;
353 }
354
355 if !self.session.wants_read() {
358 self.frontend_readiness.interest.remove(Ready::READABLE);
359 }
360 debug_assert!(
361 self.session.wants_read() || !self.frontend_readiness.interest.is_readable(),
362 "READABLE interest must be cleared once rustls stops wanting reads"
363 );
364
365 if self.session.wants_write() {
366 self.frontend_readiness.interest.insert(Ready::WRITABLE);
367 }
368
369 if self.session.is_handshaking() {
370 SessionResult::Continue
371 } else {
372 if self.session.wants_write() {
374 SessionResult::Continue
375 } else {
376 debug_assert!(
379 !self.session.is_handshaking() && !self.session.wants_write(),
380 "Upgrade requires a completed handshake with no pending output"
381 );
382 self.frontend_readiness.interest.insert(Ready::READABLE);
390 self.frontend_readiness.interest.insert(Ready::WRITABLE);
391 if let Some(elapsed_ms) = self.record_handshake_duration_ms() {
392 time!(names::tls::HANDSHAKE_MS, elapsed_ms);
393 }
394 SessionResult::Upgrade
395 }
396 }
397 }
398
399 pub fn writable(&mut self) -> SessionResult {
400 self.handshake_started_at.get_or_insert_with(Instant::now);
402 debug_assert!(
403 self.handshake_started_at.is_some(),
404 "handshake anchor must be set before driving TLS I/O"
405 );
406
407 let was_handshaking = self.session.is_handshaking();
409
410 let mut can_write = true;
411
412 loop {
413 let mut can_work = false;
414
415 if self.session.wants_write() && can_write {
416 can_work = true;
417
418 match handshake_write(&mut self.session, &mut self.stream) {
419 Ok(_) => {}
420 Err(e) => match e.kind() {
421 ErrorKind::WouldBlock => {
422 self.frontend_readiness.event.remove(Ready::WRITABLE);
423 can_write = false
424 }
425 _ => {
426 if matches!(
427 e.kind(),
428 ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted
429 ) {
430 incr!(names::rustls::WRITE_RESET);
431 }
432 error!(
433 "{} Could not perform handshake: {:?}",
434 log_context!(self),
435 e
436 );
437 return SessionResult::Close;
438 }
439 },
440 }
441
442 if let Err(e) = self.session.process_new_packets() {
443 self.log_handshake_error(&e);
444 return SessionResult::Close;
445 }
446 }
447
448 if !can_work {
449 break;
450 }
451 }
452
453 debug_assert!(
456 was_handshaking || !self.session.is_handshaking(),
457 "rustls handshake must not regress from finished back to handshaking"
458 );
459
460 if !self.session.wants_write() {
463 self.frontend_readiness.interest.remove(Ready::WRITABLE);
464 }
465 debug_assert!(
466 self.session.wants_write() || !self.frontend_readiness.interest.is_writable(),
467 "WRITABLE interest must be cleared once rustls stops wanting writes"
468 );
469
470 if self.session.wants_read() {
471 self.frontend_readiness.interest.insert(Ready::READABLE);
472 }
473
474 if self.session.is_handshaking() {
475 SessionResult::Continue
476 } else if self.session.wants_read() {
477 debug_assert!(
480 !self.session.is_handshaking(),
481 "Upgrade requires a completed handshake"
482 );
483 self.frontend_readiness.interest.insert(Ready::READABLE);
484 if let Some(elapsed_ms) = self.record_handshake_duration_ms() {
485 time!(names::tls::HANDSHAKE_MS, elapsed_ms);
486 }
487 SessionResult::Upgrade
488 } else {
489 debug_assert!(
490 !self.session.is_handshaking(),
491 "Upgrade requires a completed handshake"
492 );
493 self.frontend_readiness.interest.insert(Ready::WRITABLE);
494 self.frontend_readiness.interest.insert(Ready::READABLE);
495 if let Some(elapsed_ms) = self.record_handshake_duration_ms() {
496 time!(names::tls::HANDSHAKE_MS, elapsed_ms);
497 }
498 SessionResult::Upgrade
499 }
500 }
501
502 pub fn log_context(&self) -> LogContext<'_> {
503 LogContext {
504 session_id: self.request_id,
505 request_id: None,
506 cluster_id: None,
507 backend_id: None,
508 }
509 }
510
511 pub fn front_socket(&self) -> &TcpStream {
512 &self.stream
513 }
514
515 fn log_handshake_error(&self, err: &RustlsError) {
532 let reason = handshake_failure_reason(err);
533 debug_assert!(
537 reason.starts_with("tls.handshake.failed."),
538 "handshake failure metric {reason} escaped the tls.handshake.failed. namespace"
539 );
540 match err {
541 RustlsError::AlertReceived(_) => debug!(
542 "{} Could not perform handshake: {:?}",
543 log_context!(self),
544 err
545 ),
546 RustlsError::PeerIncompatible(_)
547 | RustlsError::PeerMisbehaved(_)
548 | RustlsError::InvalidMessage(_)
549 | RustlsError::InappropriateMessage { .. }
550 | RustlsError::InappropriateHandshakeMessage { .. }
551 | RustlsError::PeerSentOversizedRecord
552 | RustlsError::NoApplicationProtocol
553 | RustlsError::InvalidCertificate(_)
554 | RustlsError::DecryptError
555 | RustlsError::NoCertificatesPresented => warn!(
556 "{} Could not perform handshake: {:?}",
557 log_context!(self),
558 err
559 ),
560 _ => error!(
561 "{} Could not perform handshake: {:?}",
562 log_context!(self),
563 err
564 ),
565 }
566 count!(reason, 1);
567 }
568}
569
570fn handshake_failure_reason(err: &RustlsError) -> &'static str {
576 match err {
577 RustlsError::AlertReceived(_) => "tls.handshake.failed.alert_received",
578 RustlsError::PeerIncompatible(_) => "tls.handshake.failed.peer_incompatible",
579 RustlsError::PeerMisbehaved(_) => "tls.handshake.failed.peer_misbehaved",
580 RustlsError::InvalidMessage(_) => "tls.handshake.failed.invalid_message",
581 RustlsError::InappropriateMessage { .. } => "tls.handshake.failed.inappropriate_message",
582 RustlsError::InappropriateHandshakeMessage { .. } => {
583 "tls.handshake.failed.inappropriate_handshake_message"
584 }
585 RustlsError::PeerSentOversizedRecord => "tls.handshake.failed.oversized_record",
586 RustlsError::NoApplicationProtocol => "tls.handshake.failed.no_alpn",
587 RustlsError::InvalidCertificate(_) => "tls.handshake.failed.invalid_certificate",
588 RustlsError::DecryptError => "tls.handshake.failed.decrypt_error",
589 RustlsError::NoCertificatesPresented => "tls.handshake.failed.no_certificates_present",
590 _ => "tls.handshake.failed.other",
591 }
592}
593
594#[cfg(test)]
595thread_local! {
596 static HANDSHAKE_PASSES: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
599}
600
601impl TlsHandshake {
602 fn drive(&mut self) -> SessionResult {
605 let mut counter = 0;
606
607 if self.frontend_readiness.event.is_hup()
614 && !self.frontend_readiness.filter_interest().is_readable()
615 {
616 return SessionResult::Close;
617 }
618
619 while counter < MAX_LOOP_ITERATIONS {
620 #[cfg(test)]
621 HANDSHAKE_PASSES.with(|passes| passes.set(passes.get() + 1));
622 let frontend_interest = self.frontend_readiness.filter_interest();
623
624 trace!("{} Interest({:?})", log_context!(self), frontend_interest);
625 if !frontend_interest.is_readable()
627 && !frontend_interest.is_writable()
628 && !frontend_interest.is_error()
629 {
630 break;
631 }
632
633 if frontend_interest.is_readable() {
634 let protocol_result = self.readable();
635 if protocol_result != SessionResult::Continue {
636 return protocol_result;
637 }
638 }
639
640 if frontend_interest.is_writable() {
641 let protocol_result = self.writable();
642 if protocol_result != SessionResult::Continue {
643 return protocol_result;
644 }
645 }
646
647 if frontend_interest.is_error() {
648 error!("{} Front socket error, disconnecting", log_context!(self));
649 self.frontend_readiness.interest = Ready::EMPTY;
650 return SessionResult::Close;
651 }
652
653 counter += 1;
654 }
655
656 if counter >= MAX_LOOP_ITERATIONS {
657 error!(
658 "{}\tHandling session went through {} iterations, there's a probable infinite loop bug, closing the connection",
659 log_context!(self),
660 MAX_LOOP_ITERATIONS
661 );
662
663 incr!(names::http::INFINITE_LOOP_ERROR);
664 self.print_state("HTTPS");
665
666 return SessionResult::Close;
667 }
668
669 SessionResult::Continue
670 }
671}
672
673impl SessionState for TlsHandshake {
674 fn ready(
675 &mut self,
676 _session: Rc<RefCell<dyn crate::ProxySession>>,
677 _proxy: Rc<RefCell<dyn crate::L7Proxy>>,
678 _metrics: &mut SessionMetrics,
679 ) -> SessionResult {
680 self.drive()
681 }
682
683 fn update_readiness(&mut self, token: Token, events: Ready) {
684 if self.frontend_token == token {
685 self.frontend_readiness.event |= events;
686 }
687 }
688
689 fn timeout(&mut self, token: Token, _metrics: &mut SessionMetrics) -> StateResult {
690 if self.frontend_token == token {
692 self.container_frontend_timeout.triggered();
693 return StateResult::CloseSession;
694 }
695
696 error!(
697 "{}, Expect state: got timeout for an invalid token: {:?}",
698 log_context!(self),
699 token
700 );
701 StateResult::CloseSession
702 }
703
704 fn cancel_timeouts(&mut self) {
705 self.container_frontend_timeout.cancel();
706 }
707
708 fn print_state(&self, context: &str) {
709 error!(
710 "{} Session(Handshake)\n\tFrontend:\n\t\ttoken: {:?}\treadiness: {:?}",
711 context, self.frontend_token, self.frontend_readiness
712 );
713 }
714}
715
716#[cfg(test)]
720mod tests {
721 use std::collections::HashSet;
722
723 use rustls::{
724 AlertDescription, CertificateError, ContentType, Error as RustlsError, HandshakeType,
725 InvalidMessage, PeerIncompatible, PeerMisbehaved,
726 };
727
728 use mio::{Token, net::TcpStream};
729 use rusty_ulid::Ulid;
730
731 use super::{
732 HandshakeReadFault, TlsHandshake, handshake_failure_reason, handshake_read, handshake_write,
733 };
734 use crate::{
735 Ready, SessionResult, metrics::names, protocol::SessionState, timer::TimeoutContainer,
736 };
737 use std::io::ErrorKind;
738
739 #[test]
745 fn handshake_failure_reason_maps_every_variant_to_unique_namespaced_key() {
746 let cases: &[(RustlsError, &str)] = &[
747 (
748 RustlsError::AlertReceived(AlertDescription::HandshakeFailure),
749 "tls.handshake.failed.alert_received",
750 ),
751 (
752 RustlsError::PeerIncompatible(PeerIncompatible::NoCipherSuitesInCommon),
753 "tls.handshake.failed.peer_incompatible",
754 ),
755 (
756 RustlsError::PeerMisbehaved(PeerMisbehaved::IllegalMiddleboxChangeCipherSpec),
757 "tls.handshake.failed.peer_misbehaved",
758 ),
759 (
760 RustlsError::InvalidMessage(InvalidMessage::InvalidContentType),
761 "tls.handshake.failed.invalid_message",
762 ),
763 (
764 RustlsError::InappropriateMessage {
765 expect_types: vec![ContentType::Handshake],
766 got_type: ContentType::ApplicationData,
767 },
768 "tls.handshake.failed.inappropriate_message",
769 ),
770 (
771 RustlsError::InappropriateHandshakeMessage {
772 expect_types: vec![HandshakeType::ClientHello],
773 got_type: HandshakeType::Finished,
774 },
775 "tls.handshake.failed.inappropriate_handshake_message",
776 ),
777 (
778 RustlsError::PeerSentOversizedRecord,
779 "tls.handshake.failed.oversized_record",
780 ),
781 (
782 RustlsError::NoApplicationProtocol,
783 "tls.handshake.failed.no_alpn",
784 ),
785 (
786 RustlsError::InvalidCertificate(CertificateError::Expired),
787 "tls.handshake.failed.invalid_certificate",
788 ),
789 (
790 RustlsError::DecryptError,
791 "tls.handshake.failed.decrypt_error",
792 ),
793 (
794 RustlsError::NoCertificatesPresented,
795 "tls.handshake.failed.no_certificates_present",
796 ),
797 (
799 RustlsError::General("test".to_owned()),
800 "tls.handshake.failed.other",
801 ),
802 (RustlsError::EncryptError, "tls.handshake.failed.other"),
803 (
804 RustlsError::FailedToGetCurrentTime,
805 "tls.handshake.failed.other",
806 ),
807 (
808 RustlsError::HandshakeNotComplete,
809 "tls.handshake.failed.other",
810 ),
811 ];
812
813 let mut seen = HashSet::new();
814 for (err, expected) in cases {
815 let got = handshake_failure_reason(err);
816 assert_eq!(got, *expected, "variant {err:?} → {got}, want {expected}");
817 assert!(
818 got.starts_with("tls.handshake.failed."),
819 "reason {got} missing tls.handshake.failed. namespace"
820 );
821 seen.insert(got);
822 }
823
824 assert_eq!(seen.len(), 12, "unexpected key set: {seen:?}");
826 }
827
828 fn flight<D>(conn: &mut rustls::ConnectionCommon<D>) -> Vec<u8> {
830 let mut wire = Vec::new();
831 while conn.wants_write() {
832 conn.write_tls(&mut wire)
833 .expect("a TLS flight must serialize into memory");
834 }
835 wire
836 }
837
838 fn deliver(client: &mut rustls::ClientConnection, wire: &[u8]) {
840 let mut cursor = std::io::Cursor::new(wire);
841 while (cursor.position() as usize) < wire.len() {
842 client
843 .read_tls(&mut cursor)
844 .expect("the server flight must be readable from memory");
845 client
846 .process_new_packets()
847 .expect("the server flight must process cleanly");
848 }
849 }
850
851 #[test]
855 fn a_short_handshake_read_stops_without_an_eagain() {
856 use crate::socket::rustls_read_tests::{CountingTransport, fresh_pair};
857
858 let (mut server, mut client) = fresh_pair(Vec::new());
859 let hello = flight(&mut client);
860 assert!(
861 hello.len() < 4096,
862 "premise: the ClientHello is a short read"
863 );
864 let mut transport = CountingTransport {
865 wire: hello.into_iter().collect(),
866 ..Default::default()
867 };
868
869 let mut event = Ready::READABLE;
870 handshake_read(&mut server, &mut transport, &mut event)
871 .expect("the ClientHello must process");
872 assert_eq!((transport.reads, transport.eagains), (1, 0));
873 assert!(
874 !event.is_readable(),
875 "a short read proved the queue empty: READABLE must go"
876 );
877 assert!(server.is_handshaking());
878
879 deliver(&mut client, &flight(&mut server));
880 transport.wire.extend(flight(&mut client));
881 event = Ready::READABLE;
882 handshake_read(&mut server, &mut transport, &mut event)
883 .expect("the client Finished must process");
884 assert_eq!(
885 (transport.reads, transport.eagains),
886 (2, 0),
887 "the Finished costs one recv and no EAGAIN"
888 );
889 assert!(!event.is_readable());
890 assert!(!server.is_handshaking(), "the handshake is complete");
891 }
892
893 #[test]
900 fn a_reset_during_the_handshake_counts_a_read_reset() {
901 use crate::socket::{rustls_read_tests::fresh_pair, tests};
902
903 let (mut server, _client) = fresh_pair(Vec::new());
904 let mut stream = tests::reset_stream();
905 let before = tests::proxy_count(names::rustls::READ_RESET);
906
907 let mut event = Ready::READABLE;
908 let fault = handshake_read(&mut server, &mut stream, &mut event)
909 .expect_err("a reset socket cannot carry a handshake");
910 assert!(
911 matches!(&fault, HandshakeReadFault::ReadTls(e) if e.kind() == ErrorKind::ConnectionReset),
912 "the reset surfaces as a read fault, got {fault:?}"
913 );
914 assert_eq!(tests::proxy_count(names::rustls::READ_RESET) - before, 1);
915 }
916
917 #[test]
921 fn a_full_handshake_read_reads_again() {
922 use crate::socket::rustls_read_tests::{CountingTransport, fresh_pair};
923
924 let alpn = (0..64u8)
925 .map(|index| vec![b'a' + index % 26; 100])
926 .collect();
927 let (mut server, mut client) = fresh_pair(alpn);
928 let hello = flight(&mut client);
929 assert!(
930 4096 < hello.len() && hello.len() < 8192,
931 "premise: one full read and one short one, got {} bytes",
932 hello.len()
933 );
934 let mut transport = CountingTransport {
935 wire: hello.into_iter().collect(),
936 ..Default::default()
937 };
938 let mut event = Ready::READABLE;
939 handshake_read(&mut server, &mut transport, &mut event)
940 .expect("the padded ClientHello must process");
941 assert_eq!(
942 (transport.reads, transport.eagains),
943 (2, 0),
944 "a full read is followed by one more recv, which is short"
945 );
946 assert!(!event.is_readable());
947 assert!(server.wants_write(), "the whole ClientHello was processed");
948 }
949
950 struct InterruptedOnce<T> {
953 inner: T,
954 calls: usize,
955 }
956
957 impl<T> InterruptedOnce<T> {
958 fn new(inner: T) -> Self {
959 InterruptedOnce { inner, calls: 0 }
960 }
961
962 fn interrupt_first(&mut self) -> std::io::Result<()> {
963 self.calls += 1;
964 if self.calls == 1 {
965 return Err(ErrorKind::Interrupted.into());
966 }
967 Ok(())
968 }
969 }
970
971 impl<T: std::io::Read> std::io::Read for InterruptedOnce<T> {
972 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
973 self.interrupt_first()?;
974 self.inner.read(buf)
975 }
976 }
977
978 impl<T: std::io::Write> std::io::Write for InterruptedOnce<T> {
979 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
980 self.interrupt_first()?;
981 self.inner.write(buf)
982 }
983
984 fn flush(&mut self) -> std::io::Result<()> {
985 self.inner.flush()
986 }
987 }
988
989 #[test]
997 fn an_interrupted_handshake_read_is_retried() {
998 use crate::socket::rustls_read_tests::{CountingTransport, fresh_pair};
999
1000 let (mut server, mut client) = fresh_pair(Vec::new());
1001 let mut transport = InterruptedOnce::new(CountingTransport {
1002 wire: flight(&mut client).into_iter().collect(),
1003 ..Default::default()
1004 });
1005
1006 let mut event = Ready::READABLE;
1007 handshake_read(&mut server, &mut transport, &mut event)
1008 .expect("an interrupted read must be retried, not reported");
1009
1010 assert_eq!(transport.calls, 2, "one interrupted read, one retry");
1011 assert_eq!(
1012 (transport.inner.reads, transport.inner.eagains),
1013 (1, 0),
1014 "the retry is the only recv to reach the socket"
1015 );
1016 assert!(
1017 transport.inner.wire.is_empty(),
1018 "the retry read the ClientHello"
1019 );
1020 assert!(
1021 !event.is_readable(),
1022 "the retried read was short: READABLE must go"
1023 );
1024 assert!(server.wants_write(), "the whole ClientHello was processed");
1025 }
1026
1027 #[test]
1033 fn an_interrupted_handshake_write_is_retried() {
1034 use crate::socket::rustls_read_tests::fresh_pair;
1035
1036 let (mut server, mut client) = fresh_pair(Vec::new());
1037 let hello = flight(&mut client);
1038 server
1039 .read_tls(&mut std::io::Cursor::new(hello))
1040 .expect("the ClientHello must be readable from memory");
1041 server
1042 .process_new_packets()
1043 .expect("the ClientHello must process cleanly");
1044 assert!(server.wants_write(), "premise: the server flight is queued");
1045 let mut transport = InterruptedOnce::new(Vec::new());
1046
1047 let written = handshake_write(&mut server, &mut transport)
1048 .expect("an interrupted write must be retried, not reported");
1049
1050 assert_eq!(transport.calls, 2, "one interrupted write, one retry");
1051 assert!(written > 0 && transport.inner.len() == written);
1052 let mut wire = transport.inner;
1053 wire.extend(flight(&mut server));
1054 deliver(&mut client, &wire);
1055 assert!(
1056 client.wants_write(),
1057 "the client got the whole server flight and answers it"
1058 );
1059 }
1060
1061 fn hello_then_fin(hello_part: impl Fn(usize) -> usize, event: Ready) -> (SessionResult, usize) {
1065 use std::io::Write as _;
1066
1067 use crate::socket::rustls_read_tests::fresh_pair;
1068
1069 let listener = std::net::TcpListener::bind("127.0.0.1:0")
1070 .expect("test listener must bind to a loopback port");
1071 let mut peer = std::net::TcpStream::connect(
1072 listener
1073 .local_addr()
1074 .expect("test listener must report its local address"),
1075 )
1076 .expect("loopback connect must complete");
1077 let (accepted, _) = listener.accept().expect("the connection must be accepted");
1078 accepted
1079 .set_nonblocking(true)
1080 .expect("mio requires a nonblocking stream");
1081 let (server, mut client) = fresh_pair(Vec::new());
1082 let hello = flight(&mut client);
1083 peer.write_all(&hello[..hello_part(hello.len())])
1084 .expect("the client must send");
1085 peer.shutdown(std::net::Shutdown::Write)
1086 .expect("the client must send its FIN");
1087
1088 let token = Token(7);
1089 let mut handshake = TlsHandshake::new(
1090 TimeoutContainer::new_empty(std::time::Duration::from_secs(10)),
1091 server,
1092 TcpStream::from_std(accepted),
1093 token,
1094 Ulid::generate(),
1095 None,
1096 );
1097 handshake.update_readiness(token, event);
1098 super::HANDSHAKE_PASSES.with(|passes| passes.set(0));
1099 let result = handshake.drive();
1100 (result, super::HANDSHAKE_PASSES.with(|passes| passes.get()))
1101 }
1102
1103 #[test]
1112 fn a_partial_client_hello_then_fin_closes_without_spinning() {
1113 let (result, passes) = hello_then_fin(|len| len / 2, Ready::READABLE | Ready::HUP);
1114 assert_eq!(result, SessionResult::Close, "the EOF closes the handshake");
1115 assert!(
1116 passes < 4,
1117 "one event settles in a few passes, took {passes}"
1118 );
1119 }
1120
1121 #[test]
1124 fn a_full_client_hello_then_fin_closes_without_spinning() {
1125 let (result, passes) = hello_then_fin(|len| len, Ready::READABLE | Ready::HUP);
1126 assert_eq!(result, SessionResult::Close, "the EOF closes the handshake");
1127 assert!(
1128 passes < 4,
1129 "one event settles in a few passes, took {passes}"
1130 );
1131 }
1132
1133 #[test]
1136 fn a_full_client_hello_then_fin_with_writable_closes_without_spinning() {
1137 let (result, passes) =
1138 hello_then_fin(|len| len, Ready::READABLE | Ready::WRITABLE | Ready::HUP);
1139 assert_eq!(result, SessionResult::Close, "the EOF closes the handshake");
1140 assert!(
1141 passes < 4,
1142 "one event settles in a few passes, took {passes}"
1143 );
1144 }
1145
1146 fn drive(handshake: &mut TlsHandshake) -> SessionResult {
1148 for _ in 0..16 {
1149 let interest = handshake.frontend_readiness.filter_interest();
1150 if interest.is_empty() {
1151 return SessionResult::Continue;
1152 }
1153 if interest.is_readable() {
1154 let result = handshake.readable();
1155 if result != SessionResult::Continue {
1156 return result;
1157 }
1158 }
1159 if interest.is_writable() {
1160 let result = handshake.writable();
1161 if result != SessionResult::Continue {
1162 return result;
1163 }
1164 }
1165 }
1166 panic!("the handshake did not settle within 16 passes");
1167 }
1168
1169 #[test]
1177 fn a_client_hello_in_three_segments_completes_on_a_loopback_socket() {
1178 use std::io::{Read as _, Write as _};
1179
1180 use crate::socket::rustls_read_tests::fresh_pair;
1181
1182 let token = Token(7);
1183 let mut poll = mio::Poll::new().expect("a poll instance must open");
1184 let mut events = mio::Events::with_capacity(8);
1185 let listener = std::net::TcpListener::bind("127.0.0.1:0")
1186 .expect("test listener must bind to a loopback port");
1187 let mut peer = std::net::TcpStream::connect(
1188 listener
1189 .local_addr()
1190 .expect("test listener must report its local address"),
1191 )
1192 .expect("loopback connect must complete");
1193 peer.set_nodelay(true)
1194 .expect("the client must disable Nagle to send each segment at once");
1195 let (accepted, _) = listener.accept().expect("the connection must be accepted");
1196 accepted
1197 .set_nonblocking(true)
1198 .expect("mio requires a nonblocking stream");
1199 let mut stream = TcpStream::from_std(accepted);
1200 poll.registry()
1201 .register(&mut stream, token, mio::Interest::READABLE)
1202 .expect("the stream must register");
1203
1204 let (server, mut client) = fresh_pair(Vec::new());
1205 let mut handshake = TlsHandshake::new(
1206 TimeoutContainer::new_empty(std::time::Duration::from_secs(10)),
1207 server,
1208 stream,
1209 token,
1210 Ulid::generate(),
1211 None,
1212 );
1213 let mut edge_within = |poll: &mut mio::Poll, timeout: std::time::Duration| {
1214 poll.poll(&mut events, Some(timeout))
1215 .expect("poll must succeed");
1216 events
1217 .iter()
1218 .any(|event| event.token() == token && event.is_readable())
1219 };
1220 let edge = std::time::Duration::from_secs(5);
1221 let quiet = std::time::Duration::from_millis(50);
1222
1223 let hello = flight(&mut client);
1224 let third = hello.len() / 3;
1225 let segments = [
1226 &hello[..third],
1227 &hello[third..2 * third],
1228 &hello[2 * third..],
1229 ];
1230 for (index, segment) in segments.iter().enumerate() {
1231 peer.write_all(segment).expect("the client must send");
1232 assert!(
1233 edge_within(&mut poll, edge),
1234 "segment {index} must raise an edge"
1235 );
1236 handshake.update_readiness(token, Ready::READABLE);
1237 assert_eq!(drive(&mut handshake), SessionResult::Continue);
1238 assert!(
1239 !handshake.frontend_readiness.event.is_readable(),
1240 "segment {index}: the short read must drop READABLE"
1241 );
1242 if index + 1 < segments.len() {
1243 assert!(handshake.session.is_handshaking());
1244 assert!(
1245 !edge_within(&mut poll, quiet),
1246 "segment {index}: edge-triggered, nothing new, no event"
1247 );
1248 let mut probe = [0u8; 1];
1249 assert!(
1250 matches!(
1251 handshake.stream.read(&mut probe),
1252 Err(ref e) if e.kind() == ErrorKind::WouldBlock
1253 ),
1254 "segment {index}: nothing is left queued"
1255 );
1256 }
1257 }
1258 assert!(
1259 handshake.session.wants_write(),
1260 "the whole ClientHello was read and processed"
1261 );
1262
1263 handshake.update_readiness(token, Ready::WRITABLE);
1265 assert_eq!(drive(&mut handshake), SessionResult::Continue);
1266 assert!(!handshake.session.wants_write(), "the server flight is out");
1267
1268 peer.set_read_timeout(Some(std::time::Duration::from_secs(5)))
1269 .expect("the client read timeout must set");
1270 while client.is_handshaking() {
1271 client
1272 .read_tls(&mut peer)
1273 .expect("the client must read the server flight");
1274 client
1275 .process_new_packets()
1276 .expect("the server flight must process cleanly");
1277 }
1278 peer.write_all(&flight(&mut client))
1279 .expect("the client must send its Finished");
1280 assert!(
1281 edge_within(&mut poll, edge),
1282 "the Finished must raise an edge"
1283 );
1284 handshake.update_readiness(token, Ready::READABLE);
1285 assert_eq!(drive(&mut handshake), SessionResult::Upgrade);
1286 assert!(!handshake.session.is_handshaking());
1287 assert!(
1288 !handshake.frontend_readiness.event.is_readable(),
1289 "the socket is empty: the upgrade must not be handed a READABLE"
1290 );
1291 }
1292}