Skip to content

Commit 30cceb9

Browse files
HMBSbigealgesten
authored andcommitted
feat: Add protocol_version() accessor to Dtls
1 parent e8cbda9 commit 30cceb9

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,18 @@ impl Dtls {
276276
Dtls { inner: Some(inner) }
277277
}
278278

279+
/// Returns the negotiated DTLS protocol version.
280+
///
281+
/// Returns `None` for auto-sense instances that have not yet completed
282+
/// version negotiation (i.e. still in a `Pending` state).
283+
pub fn protocol_version(&self) -> Option<ProtocolVersion> {
284+
match self.inner.as_ref()? {
285+
Inner::Client12(_) | Inner::Server12(_) => Some(ProtocolVersion::DTLS1_2),
286+
Inner::Client13(_) | Inner::Server13(_) => Some(ProtocolVersion::DTLS1_3),
287+
Inner::ServerPending(_) | Inner::ClientPending(_) => None,
288+
}
289+
}
290+
279291
/// Return true if the instance is operating in the client role.
280292
pub fn is_active(&self) -> bool {
281293
matches!(
@@ -590,4 +602,23 @@ mod test {
590602
is_unwind_safe(new_instance_13());
591603
is_unwind_safe(new_instance_auto());
592604
}
605+
606+
#[test]
607+
fn test_protocol_version_12() {
608+
let dtls = new_instance();
609+
assert_eq!(dtls.protocol_version(), Some(ProtocolVersion::DTLS1_2));
610+
}
611+
612+
#[test]
613+
fn test_protocol_version_13() {
614+
let dtls = new_instance_13();
615+
assert_eq!(dtls.protocol_version(), Some(ProtocolVersion::DTLS1_3));
616+
}
617+
618+
#[test]
619+
fn test_protocol_version_auto_pending() {
620+
let dtls = new_instance_auto();
621+
// Auto-sense instance before negotiation should return None
622+
assert_eq!(dtls.protocol_version(), None);
623+
}
593624
}

tests/auto/handshake.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,119 @@ fn auto_client_rejects_unknown_version_response() {
598598
other => panic!("expected UnexpectedMessage, got: {other:?}"),
599599
}
600600
}
601+
602+
#[test]
603+
#[cfg(feature = "rcgen")]
604+
fn auto_client_protocol_version_after_negotiating_dtls13() {
605+
//! After completing a handshake against a DTLS 1.3 server, the
606+
//! auto-sense client should report `Some(ProtocolVersion::DTLS1_3)`.
607+
use dimpl::certificate::generate_self_signed_certificate;
608+
use dimpl::ProtocolVersion;
609+
610+
let _ = env_logger::try_init();
611+
612+
let client_cert = generate_self_signed_certificate().expect("gen client cert");
613+
let server_cert = generate_self_signed_certificate().expect("gen server cert");
614+
615+
let config = default_config();
616+
let mut now = Instant::now();
617+
618+
let mut client = Dtls::new_auto(Arc::clone(&config), client_cert, now);
619+
client.set_active(true);
620+
621+
let mut server = Dtls::new_13(config, server_cert, now);
622+
server.set_active(false);
623+
624+
// Before negotiation, auto-sense returns None.
625+
assert_eq!(client.protocol_version(), None);
626+
627+
let mut client_connected = false;
628+
let mut server_connected = false;
629+
630+
for _ in 0..40 {
631+
client.handle_timeout(now).expect("client timeout");
632+
server.handle_timeout(now).expect("server timeout");
633+
634+
let client_out = drain_outputs(&mut client);
635+
let server_out = drain_outputs(&mut server);
636+
637+
if client_out.connected {
638+
client_connected = true;
639+
}
640+
if server_out.connected {
641+
server_connected = true;
642+
}
643+
644+
deliver_packets(&client_out.packets, &mut server);
645+
deliver_packets(&server_out.packets, &mut client);
646+
647+
if client_connected && server_connected {
648+
break;
649+
}
650+
now += Duration::from_millis(10);
651+
}
652+
653+
assert!(
654+
client_connected && server_connected,
655+
"Handshake should complete"
656+
);
657+
assert_eq!(client.protocol_version(), Some(ProtocolVersion::DTLS1_3));
658+
}
659+
660+
#[test]
661+
#[cfg(feature = "rcgen")]
662+
fn auto_client_protocol_version_after_negotiating_dtls12() {
663+
//! After completing a handshake against a DTLS 1.2 server, the
664+
//! auto-sense client should report `Some(ProtocolVersion::DTLS1_2)`.
665+
use dimpl::certificate::generate_self_signed_certificate;
666+
use dimpl::ProtocolVersion;
667+
668+
let _ = env_logger::try_init();
669+
670+
let client_cert = generate_self_signed_certificate().expect("gen client cert");
671+
let server_cert = generate_self_signed_certificate().expect("gen server cert");
672+
673+
let config = default_config();
674+
let mut now = Instant::now();
675+
676+
let mut client = Dtls::new_auto(Arc::clone(&config), client_cert, now);
677+
client.set_active(true);
678+
679+
let mut server = Dtls::new_12(config, server_cert, now);
680+
server.set_active(false);
681+
682+
// Before negotiation, auto-sense returns None.
683+
assert_eq!(client.protocol_version(), None);
684+
685+
let mut client_connected = false;
686+
let mut server_connected = false;
687+
688+
for _ in 0..40 {
689+
client.handle_timeout(now).expect("client timeout");
690+
server.handle_timeout(now).expect("server timeout");
691+
692+
let client_out = drain_outputs(&mut client);
693+
let server_out = drain_outputs(&mut server);
694+
695+
if client_out.connected {
696+
client_connected = true;
697+
}
698+
if server_out.connected {
699+
server_connected = true;
700+
}
701+
702+
deliver_packets(&client_out.packets, &mut server);
703+
deliver_packets(&server_out.packets, &mut client);
704+
705+
if client_connected && server_connected {
706+
break;
707+
}
708+
now += Duration::from_millis(10);
709+
}
710+
711+
assert!(
712+
client_connected && server_connected,
713+
"Handshake should complete"
714+
);
715+
assert_eq!(client.protocol_version(), Some(ProtocolVersion::DTLS1_2));
716+
}

0 commit comments

Comments
 (0)