1use std::sync::Arc;
2
3use bytes::{Buf, Bytes, BytesMut};
4
5use crate::draft15::endpoint::{Endpoint, EndpointError};
6use crate::draft15::event::{ClientEvent, Direction, StreamKind};
7use crate::draft15::observer::ConnectionObserver;
8use crate::draft15::session::request_id::Role;
9use crate::transport::quic::QuicTransport;
10use crate::transport::{RecvStream, SendStream, Transport, TransportError};
11use moqtap_codec::dispatch::{
12 AnyControlMessage, AnyDatagramHeader, AnyFetchHeader, AnySubgroupHeader,
13};
14use moqtap_codec::draft15::data_stream::{FetchHeader, SubgroupObject, SubgroupObjectReader};
15use moqtap_codec::draft15::message::ControlMessage;
16use moqtap_codec::error::CodecError;
17use moqtap_codec::kvp::KeyValuePair;
18use moqtap_codec::types::*;
19use moqtap_codec::varint::VarInt;
20use moqtap_codec::version::DraftVersion;
21
22pub const MOQT_ALPN: &[u8] = b"moq-00";
24
25#[derive(Debug, thiserror::Error)]
27pub enum ConnectionError {
28 #[error("endpoint error: {0}")]
30 Endpoint(#[from] EndpointError),
31 #[error("codec error: {0}")]
33 Codec(#[from] CodecError),
34 #[error("transport error: {0}")]
36 Transport(#[from] TransportError),
37 #[error("varint error: {0}")]
39 VarInt(#[from] moqtap_codec::varint::VarIntError),
40 #[error("control stream not open")]
42 NoControlStream,
43 #[error("unexpected end of stream")]
45 UnexpectedEnd,
46 #[error("stream finished")]
48 StreamFinished,
49 #[error("invalid server address: {0}")]
51 InvalidAddress(String),
52 #[error("TLS config error: {0}")]
54 TlsConfig(String),
55 #[error("data stream state error: {0}")]
57 DataStreamState(&'static str),
58}
59
60#[derive(Debug, Clone)]
62pub enum TransportType {
63 Quic,
65 WebTransport {
67 url: String,
69 },
70}
71
72pub struct ClientConfig {
76 pub draft: DraftVersion,
78 pub transport: TransportType,
80 pub skip_cert_verification: bool,
82 pub ca_certs: Vec<Vec<u8>>,
84 pub setup_parameters: Vec<KeyValuePair>,
86}
87
88impl ClientConfig {
89 pub fn alpn(&self) -> Vec<Vec<u8>> {
91 match &self.transport {
92 TransportType::Quic => vec![self.draft.quic_alpn().to_vec()],
93 TransportType::WebTransport { .. } => vec![b"h3".to_vec()],
94 }
95 }
96}
97
98pub struct FramedSendStream {
100 inner: SendStream,
101 draft: DraftVersion,
102 subgroup_io: Option<SubgroupObjectReader>,
106}
107
108impl FramedSendStream {
109 pub fn new(inner: SendStream, draft: DraftVersion) -> Self {
111 Self { inner, draft, subgroup_io: None }
112 }
113
114 pub fn stream_id(&self) -> u64 {
116 self.inner.stream_id()
117 }
118
119 pub async fn write_control(
122 &mut self,
123 msg: &AnyControlMessage,
124 ) -> Result<Vec<u8>, ConnectionError> {
125 let mut buf = Vec::new();
126 msg.encode(&mut buf)?;
127 self.inner.write_all(&buf).await?;
128 Ok(buf)
129 }
130
131 pub async fn write_subgroup_header(
135 &mut self,
136 header: &AnySubgroupHeader,
137 ) -> Result<(), ConnectionError> {
138 let mut buf = Vec::new();
139 header.encode(&mut buf);
140 self.inner.write_all(&buf).await?;
141 if let AnySubgroupHeader::Draft15(ref d15) = header {
142 self.subgroup_io = Some(SubgroupObjectReader::new(d15));
143 }
144 Ok(())
145 }
146
147 pub async fn write_fetch_header(
149 &mut self,
150 header: &AnyFetchHeader,
151 ) -> Result<(), ConnectionError> {
152 let mut buf = Vec::new();
153 header.encode(&mut buf);
154 self.inner.write_all(&buf).await?;
155 Ok(())
156 }
157
158 pub async fn write_subgroup_object(
163 &mut self,
164 object: &SubgroupObject,
165 ) -> Result<(), ConnectionError> {
166 let writer = self
167 .subgroup_io
168 .as_mut()
169 .ok_or(ConnectionError::DataStreamState("subgroup header not written yet"))?;
170 let mut buf = Vec::new();
171 writer.write_object(object, &mut buf)?;
172 self.inner.write_all(&buf).await?;
173 Ok(())
174 }
175
176 pub async fn finish(&mut self) -> Result<(), ConnectionError> {
178 self.inner.finish()?;
179 Ok(())
180 }
181
182 pub fn draft(&self) -> DraftVersion {
184 self.draft
185 }
186}
187
188pub struct FramedRecvStream {
190 inner: RecvStream,
191 buf: BytesMut,
192 draft: DraftVersion,
193 subgroup_io: Option<SubgroupObjectReader>,
196}
197
198impl FramedRecvStream {
199 pub fn new(inner: RecvStream, draft: DraftVersion) -> Self {
201 Self { inner, buf: BytesMut::with_capacity(4096), draft, subgroup_io: None }
202 }
203
204 pub fn stream_id(&self) -> u64 {
206 self.inner.stream_id()
207 }
208
209 async fn fill(&mut self) -> Result<bool, ConnectionError> {
211 let mut tmp = [0u8; 4096];
212 match self.inner.read(&mut tmp).await {
213 Ok(Some(n)) => {
214 self.buf.extend_from_slice(&tmp[..n]);
215 Ok(true)
216 }
217 Ok(None) => Ok(false),
218 Err(e) => Err(ConnectionError::Transport(e)),
219 }
220 }
221
222 async fn ensure(&mut self, n: usize) -> Result<(), ConnectionError> {
224 while self.buf.len() < n {
225 if !self.fill().await? {
226 return Err(ConnectionError::UnexpectedEnd);
227 }
228 }
229 Ok(())
230 }
231
232 pub async fn read_control(
238 &mut self,
239 capture_raw: bool,
240 ) -> Result<(AnyControlMessage, Option<Vec<u8>>), ConnectionError> {
241 self.ensure(1).await?;
243 let type_len = varint_len(self.buf[0]);
244 self.ensure(type_len).await?;
245
246 let mut cursor = &self.buf[..type_len];
247 let _type_id = VarInt::decode(&mut cursor)?;
248
249 let (payload_len, len_field_size) = if self.draft.uses_fixed_length_framing() {
251 self.ensure(type_len + 2).await?;
252 let hi = self.buf[type_len] as usize;
253 let lo = self.buf[type_len + 1] as usize;
254 ((hi << 8) | lo, 2)
255 } else {
256 self.ensure(type_len + 1).await?;
257 let payload_len_start = type_len;
258 let payload_len_varint_len = varint_len(self.buf[payload_len_start]);
259 self.ensure(type_len + payload_len_varint_len).await?;
260 let mut cursor = &self.buf[payload_len_start..type_len + payload_len_varint_len];
261 let payload_len = VarInt::decode(&mut cursor)?.into_inner() as usize;
262 (payload_len, payload_len_varint_len)
263 };
264
265 let total = type_len + len_field_size + payload_len;
267 self.ensure(total).await?;
268
269 let raw = capture_raw.then(|| self.buf[..total].to_vec());
271
272 let mut frame = &self.buf[..total];
274 let msg = AnyControlMessage::decode(self.draft, &mut frame)?;
275 self.buf.advance(total);
276 Ok((msg, raw))
277 }
278
279 pub async fn read_subgroup_header(&mut self) -> Result<AnySubgroupHeader, ConnectionError> {
282 self.ensure(1).await?;
283 loop {
284 let mut cursor = &self.buf[..];
285 match AnySubgroupHeader::decode(self.draft, &mut cursor) {
286 Ok(header) => {
287 let consumed = self.buf.len() - cursor.remaining();
288 self.buf.advance(consumed);
289 if let AnySubgroupHeader::Draft15(ref d15) = header {
290 self.subgroup_io = Some(SubgroupObjectReader::new(d15));
291 }
292 return Ok(header);
293 }
294 Err(CodecError::UnexpectedEnd) => {
295 if !self.fill().await? {
296 return Err(ConnectionError::UnexpectedEnd);
297 }
298 }
299 Err(e) => return Err(ConnectionError::Codec(e)),
300 }
301 }
302 }
303
304 pub async fn read_fetch_header(&mut self) -> Result<AnyFetchHeader, ConnectionError> {
306 self.ensure(1).await?;
307 loop {
308 let mut cursor = &self.buf[..];
309 match AnyFetchHeader::decode(self.draft, &mut cursor) {
310 Ok(header) => {
311 let consumed = self.buf.len() - cursor.remaining();
312 self.buf.advance(consumed);
313 return Ok(header);
314 }
315 Err(CodecError::UnexpectedEnd) => {
316 if !self.fill().await? {
317 return Err(ConnectionError::UnexpectedEnd);
318 }
319 }
320 Err(e) => return Err(ConnectionError::Codec(e)),
321 }
322 }
323 }
324
325 pub async fn read_subgroup_object(&mut self) -> Result<SubgroupObject, ConnectionError> {
332 if self.subgroup_io.is_none() {
333 return Err(ConnectionError::DataStreamState("subgroup header not read yet"));
334 }
335 loop {
336 let reader = self.subgroup_io.as_mut().unwrap();
337 let mut probe = reader.clone();
338 let mut cursor = &self.buf[..];
339 match probe.read_object(&mut cursor) {
340 Ok(obj) => {
341 let consumed = self.buf.len() - cursor.remaining();
342 self.buf.advance(consumed);
343 *reader = probe;
344 return Ok(obj);
345 }
346 Err(CodecError::UnexpectedEnd) => {
347 if !self.fill().await? {
348 return Err(ConnectionError::UnexpectedEnd);
349 }
350 }
351 Err(e) => return Err(ConnectionError::Codec(e)),
352 }
353 }
354 }
355
356 pub async fn read_fetch_stream_header(&mut self) -> Result<FetchHeader, ConnectionError> {
358 loop {
359 let mut cursor = &self.buf[..];
360 match FetchHeader::decode(&mut cursor) {
361 Ok(hdr) => {
362 let consumed = self.buf.len() - cursor.remaining();
363 self.buf.advance(consumed);
364 return Ok(hdr);
365 }
366 Err(CodecError::UnexpectedEnd) => {
367 if !self.fill().await? {
368 return Err(ConnectionError::UnexpectedEnd);
369 }
370 }
371 Err(e) => return Err(ConnectionError::Codec(e)),
372 }
373 }
374 }
375
376 pub fn draft(&self) -> DraftVersion {
378 self.draft
379 }
380}
381
382pub struct Connection {
385 transport: Transport,
386 endpoint: Endpoint,
387 draft: DraftVersion,
388 control_send: Option<FramedSendStream>,
389 control_recv: Option<FramedRecvStream>,
390 observer: Option<Box<dyn ConnectionObserver>>,
391 pending_events: Vec<ClientEvent>,
395}
396
397impl Connection {
398 pub async fn connect(addr: &str, config: ClientConfig) -> Result<Self, ConnectionError> {
405 let draft = config.draft;
406 let transport = match &config.transport {
407 TransportType::Quic => Self::connect_quic(addr, &config).await?,
408 TransportType::WebTransport { url } => {
409 let url = url.clone();
410 Self::connect_webtransport(&url, &config).await?
411 }
412 };
413
414 let (send, recv) = transport.open_bi().await?;
416 let mut control_send = FramedSendStream::new(send, draft);
417 let mut control_recv = FramedRecvStream::new(recv, draft);
418
419 let mut endpoint = Endpoint::new(Role::Client);
421 endpoint.connect()?;
422 let setup_msg = endpoint.send_client_setup(config.setup_parameters.clone())?;
423 let any_setup = AnyControlMessage::Draft15(setup_msg);
424 let raw_setup = control_send.write_control(&any_setup).await?;
425
426 let (server_setup, raw_server_setup) = control_recv.read_control(true).await?;
427 match &server_setup {
429 AnyControlMessage::Draft15(ControlMessage::ServerSetup(ref ss)) => {
430 endpoint.receive_server_setup(ss)?;
431 }
432 _ => {
433 return Err(ConnectionError::Endpoint(EndpointError::NotActive));
434 }
435 }
436
437 let mut pending_events = Vec::with_capacity(3);
438 pending_events.push(ClientEvent::ControlMessage {
439 direction: Direction::Send,
440 message: any_setup,
441 raw: Some(raw_setup),
442 });
443 pending_events.push(ClientEvent::ControlMessage {
444 direction: Direction::Receive,
445 message: server_setup,
446 raw: raw_server_setup,
447 });
448 pending_events.push(ClientEvent::SetupComplete { negotiated_version: 0xff000000 + 15 });
449
450 Ok(Self {
451 transport,
452 endpoint,
453 draft,
454 control_send: Some(control_send),
455 control_recv: Some(control_recv),
456 observer: None,
457 pending_events,
458 })
459 }
460
461 async fn connect_quic(addr: &str, config: &ClientConfig) -> Result<Transport, ConnectionError> {
463 let server_addr = addr.parse().map_err(|e: std::net::AddrParseError| {
464 ConnectionError::InvalidAddress(e.to_string())
465 })?;
466
467 let mut tls_config = if config.skip_cert_verification {
469 rustls::ClientConfig::builder()
470 .dangerous()
471 .with_custom_certificate_verifier(Arc::new(SkipVerification))
472 .with_no_client_auth()
473 } else {
474 let mut roots = rustls::RootCertStore::empty();
475 roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
476 for der in &config.ca_certs {
477 roots
478 .add(rustls::pki_types::CertificateDer::from(der.clone()))
479 .map_err(|e| ConnectionError::TlsConfig(format!("bad CA cert: {e}")))?;
480 }
481 rustls::ClientConfig::builder().with_root_certificates(roots).with_no_client_auth()
482 };
483
484 tls_config.alpn_protocols = config.alpn();
485
486 let quic_config: quinn::crypto::rustls::QuicClientConfig =
487 tls_config.try_into().map_err(|e| ConnectionError::TlsConfig(format!("{e}")))?;
488 let client_config = quinn::ClientConfig::new(Arc::new(quic_config));
489
490 let mut quinn_endpoint = quinn::Endpoint::client("0.0.0.0:0".parse().unwrap())
491 .map_err(|e| ConnectionError::InvalidAddress(e.to_string()))?;
492 quinn_endpoint.set_default_client_config(client_config);
493
494 let server_name = addr.split(':').next().unwrap_or("localhost").to_string();
495
496 let quic = quinn_endpoint
497 .connect(server_addr, &server_name)
498 .map_err(TransportError::from)?
499 .await
500 .map_err(TransportError::from)?;
501
502 Ok(Transport::Quic(QuicTransport::new(quic)))
503 }
504
505 #[cfg(feature = "webtransport")]
507 async fn connect_webtransport(
508 url: &str,
509 config: &ClientConfig,
510 ) -> Result<Transport, ConnectionError> {
511 use crate::transport::webtransport::WebTransportTransport;
512
513 let wt_config = if config.skip_cert_verification {
514 wtransport::ClientConfig::builder()
515 .with_bind_default()
516 .with_no_cert_validation()
517 .build()
518 } else {
519 wtransport::ClientConfig::builder().with_bind_default().with_native_certs().build()
520 };
521
522 let endpoint = wtransport::Endpoint::client(wt_config)
523 .map_err(|e| ConnectionError::Transport(TransportError::Connect(e.to_string())))?;
524
525 let connection = endpoint
526 .connect(url)
527 .await
528 .map_err(|e| ConnectionError::Transport(TransportError::Connect(e.to_string())))?;
529
530 Ok(Transport::WebTransport(WebTransportTransport::new(connection)))
531 }
532
533 #[cfg(not(feature = "webtransport"))]
535 async fn connect_webtransport(
536 _url: &str,
537 _config: &ClientConfig,
538 ) -> Result<Transport, ConnectionError> {
539 Err(ConnectionError::Transport(TransportError::Connect(
540 "webtransport feature not enabled".into(),
541 )))
542 }
543
544 pub fn set_observer(&mut self, observer: Box<dyn ConnectionObserver>) {
549 self.observer = Some(observer);
550 for event in self.pending_events.drain(..) {
551 if let Some(ref obs) = self.observer {
552 obs.on_event_owned(event);
553 }
554 }
555 }
556
557 pub fn clear_observer(&mut self) {
559 self.observer = None;
560 }
561
562 fn emit(&self, event: ClientEvent) {
564 if let Some(ref obs) = self.observer {
565 obs.on_event_owned(event);
566 }
567 }
568
569 pub async fn send_control(&mut self, msg: &ControlMessage) -> Result<(), ConnectionError> {
576 let any = AnyControlMessage::Draft15(msg.clone());
577 let send = self.control_send.as_mut().ok_or(ConnectionError::NoControlStream)?;
578 let raw = send.write_control(&any).await?;
579 self.emit(ClientEvent::ControlMessage {
580 direction: Direction::Send,
581 message: any,
582 raw: Some(raw),
583 });
584 Ok(())
585 }
586
587 pub async fn recv_control(&mut self) -> Result<ControlMessage, ConnectionError> {
592 let recv = self.control_recv.as_mut().ok_or(ConnectionError::NoControlStream)?;
593 let capture_raw = self.observer.is_some();
594 let (any, raw) = recv.read_control(capture_raw).await?;
595 if capture_raw {
596 self.emit(ClientEvent::ControlMessage {
597 direction: Direction::Receive,
598 message: any.clone(),
599 raw,
600 });
601 }
602 match any {
604 AnyControlMessage::Draft15(msg) => Ok(msg),
605 _ => Err(ConnectionError::Codec(CodecError::UnknownMessageType(0))),
606 }
607 }
608
609 pub async fn recv_and_dispatch(&mut self) -> Result<ControlMessage, ConnectionError> {
612 let msg = self.recv_control().await?;
613 self.endpoint.receive_message(msg.clone())?;
614
615 if let ControlMessage::GoAway(ref ga) = msg {
617 self.emit(ClientEvent::Draining { new_session_uri: ga.new_session_uri.clone() });
618 }
619
620 Ok(msg)
621 }
622
623 pub async fn subscribe(
627 &mut self,
628 track_namespace: TrackNamespace,
629 track_name: Vec<u8>,
630 parameters: Vec<KeyValuePair>,
631 ) -> Result<VarInt, ConnectionError> {
632 let (req_id, msg) = self.endpoint.subscribe(track_namespace, track_name, parameters)?;
633 self.send_control(&msg).await?;
634 Ok(req_id)
635 }
636
637 pub async fn unsubscribe(&mut self, request_id: VarInt) -> Result<(), ConnectionError> {
639 let msg = self.endpoint.unsubscribe(request_id)?;
640 self.send_control(&msg).await
641 }
642
643 pub async fn fetch(
647 &mut self,
648 track_namespace: TrackNamespace,
649 track_name: Vec<u8>,
650 start_group: VarInt,
651 start_object: VarInt,
652 end_group: VarInt,
653 end_object: VarInt,
654 ) -> Result<VarInt, ConnectionError> {
655 let (req_id, msg) = self.endpoint.fetch(
656 track_namespace,
657 track_name,
658 start_group,
659 start_object,
660 end_group,
661 end_object,
662 )?;
663 self.send_control(&msg).await?;
664 Ok(req_id)
665 }
666
667 pub async fn joining_fetch(
669 &mut self,
670 joining_request_id: VarInt,
671 joining_start: VarInt,
672 ) -> Result<VarInt, ConnectionError> {
673 let (req_id, msg) = self.endpoint.joining_fetch(joining_request_id, joining_start)?;
674 self.send_control(&msg).await?;
675 Ok(req_id)
676 }
677
678 pub async fn fetch_cancel(&mut self, request_id: VarInt) -> Result<(), ConnectionError> {
680 let msg = self.endpoint.fetch_cancel(request_id)?;
681 self.send_control(&msg).await
682 }
683
684 pub async fn subscribe_namespace(
688 &mut self,
689 namespace_prefix: TrackNamespace,
690 parameters: Vec<KeyValuePair>,
691 ) -> Result<VarInt, ConnectionError> {
692 let (req_id, msg) = self.endpoint.subscribe_namespace(namespace_prefix, parameters)?;
693 self.send_control(&msg).await?;
694 Ok(req_id)
695 }
696
697 pub async fn publish_namespace(
699 &mut self,
700 track_namespace: TrackNamespace,
701 parameters: Vec<KeyValuePair>,
702 ) -> Result<VarInt, ConnectionError> {
703 let (req_id, msg) = self.endpoint.publish_namespace(track_namespace, parameters)?;
704 self.send_control(&msg).await?;
705 Ok(req_id)
706 }
707
708 pub async fn track_status(
712 &mut self,
713 track_namespace: TrackNamespace,
714 track_name: Vec<u8>,
715 parameters: Vec<KeyValuePair>,
716 ) -> Result<VarInt, ConnectionError> {
717 let (req_id, msg) = self.endpoint.track_status(track_namespace, track_name, parameters)?;
718 self.send_control(&msg).await?;
719 Ok(req_id)
720 }
721
722 pub async fn publish(
726 &mut self,
727 track_namespace: TrackNamespace,
728 track_name: Vec<u8>,
729 track_alias: VarInt,
730 parameters: Vec<KeyValuePair>,
731 ) -> Result<VarInt, ConnectionError> {
732 let (req_id, msg) =
733 self.endpoint.publish(track_namespace, track_name, track_alias, parameters)?;
734 self.send_control(&msg).await?;
735 Ok(req_id)
736 }
737
738 pub async fn publish_done(
740 &mut self,
741 request_id: VarInt,
742 status_code: VarInt,
743 stream_count: VarInt,
744 reason_phrase: Vec<u8>,
745 ) -> Result<(), ConnectionError> {
746 let msg = self.endpoint.send_publish_done(
747 request_id,
748 status_code,
749 stream_count,
750 reason_phrase,
751 )?;
752 self.send_control(&msg).await
753 }
754
755 pub async fn open_subgroup_stream(
759 &self,
760 header: &AnySubgroupHeader,
761 ) -> Result<FramedSendStream, ConnectionError> {
762 let send = self.transport.open_uni().await?;
763 let mut framed = FramedSendStream::new(send, self.draft);
764 let sid = framed.stream_id();
765 framed.write_subgroup_header(header).await?;
766 self.emit(ClientEvent::StreamOpened {
767 direction: Direction::Send,
768 stream_kind: StreamKind::Subgroup,
769 stream_id: sid,
770 });
771 self.emit(ClientEvent::DataStreamHeader {
772 stream_id: sid,
773 direction: Direction::Send,
774 header: header.clone(),
775 });
776 Ok(framed)
777 }
778
779 pub async fn accept_subgroup_stream(
782 &self,
783 ) -> Result<(AnySubgroupHeader, FramedRecvStream), ConnectionError> {
784 let recv = self.transport.accept_uni().await?;
785 let mut framed = FramedRecvStream::new(recv, self.draft);
786 let sid = framed.stream_id();
787 let header = framed.read_subgroup_header().await?;
788 self.emit(ClientEvent::StreamOpened {
789 direction: Direction::Receive,
790 stream_kind: StreamKind::Subgroup,
791 stream_id: sid,
792 });
793 self.emit(ClientEvent::DataStreamHeader {
794 stream_id: sid,
795 direction: Direction::Receive,
796 header: header.clone(),
797 });
798 Ok((header, framed))
799 }
800
801 pub fn send_datagram(
803 &self,
804 header: &AnyDatagramHeader,
805 payload: &[u8],
806 ) -> Result<(), ConnectionError> {
807 let mut buf = Vec::new();
808 header.encode(&mut buf);
809 buf.extend_from_slice(payload);
810 self.emit(ClientEvent::DatagramReceived {
811 direction: Direction::Send,
812 header: header.clone(),
813 payload_len: payload.len(),
814 });
815 self.transport.send_datagram(bytes::Bytes::from(buf))?;
816 Ok(())
817 }
818
819 pub async fn recv_datagram(&self) -> Result<(AnyDatagramHeader, Bytes), ConnectionError> {
821 let data = self.transport.recv_datagram().await?;
822 let mut cursor = &data[..];
823 let header = AnyDatagramHeader::decode(self.draft, &mut cursor)?;
824 let consumed = data.len() - cursor.len();
825 let payload = data.slice(consumed..);
826 self.emit(ClientEvent::DatagramReceived {
827 direction: Direction::Receive,
828 header: header.clone(),
829 payload_len: payload.len(),
830 });
831 Ok((header, payload))
832 }
833
834 pub fn endpoint(&self) -> &Endpoint {
838 &self.endpoint
839 }
840
841 pub fn endpoint_mut(&mut self) -> &mut Endpoint {
843 &mut self.endpoint
844 }
845
846 pub fn draft(&self) -> DraftVersion {
848 self.draft
849 }
850
851 pub fn close(&self, code: u32, reason: &[u8]) {
853 self.emit(ClientEvent::Closed { code, reason: reason.to_vec() });
854 self.transport.close(code, reason);
855 }
856}
857
858fn varint_len(first_byte: u8) -> usize {
860 1 << (first_byte >> 6)
861}
862
863#[derive(Debug)]
865struct SkipVerification;
866
867impl rustls::client::danger::ServerCertVerifier for SkipVerification {
868 fn verify_server_cert(
869 &self,
870 _end_entity: &rustls::pki_types::CertificateDer<'_>,
871 _intermediates: &[rustls::pki_types::CertificateDer<'_>],
872 _server_name: &rustls::pki_types::ServerName<'_>,
873 _ocsp_response: &[u8],
874 _now: rustls::pki_types::UnixTime,
875 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
876 Ok(rustls::client::danger::ServerCertVerified::assertion())
877 }
878
879 fn verify_tls12_signature(
880 &self,
881 _message: &[u8],
882 _cert: &rustls::pki_types::CertificateDer<'_>,
883 _dcs: &rustls::DigitallySignedStruct,
884 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
885 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
886 }
887
888 fn verify_tls13_signature(
889 &self,
890 _message: &[u8],
891 _cert: &rustls::pki_types::CertificateDer<'_>,
892 _dcs: &rustls::DigitallySignedStruct,
893 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
894 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
895 }
896
897 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
898 vec![
899 rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
900 rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
901 rustls::SignatureScheme::ED25519,
902 rustls::SignatureScheme::RSA_PSS_SHA256,
903 rustls::SignatureScheme::RSA_PSS_SHA384,
904 rustls::SignatureScheme::RSA_PSS_SHA512,
905 ]
906 }
907}
908
909#[cfg(test)]
910mod tests {
911 use super::*;
912
913 #[test]
914 fn varint_len_single_byte() {
915 assert_eq!(varint_len(0x00), 1);
916 assert_eq!(varint_len(0x3F), 1);
917 }
918
919 #[test]
920 fn varint_len_two_bytes() {
921 assert_eq!(varint_len(0x40), 2);
922 assert_eq!(varint_len(0x7F), 2);
923 }
924
925 #[test]
926 fn varint_len_four_bytes() {
927 assert_eq!(varint_len(0x80), 4);
928 assert_eq!(varint_len(0xBF), 4);
929 }
930
931 #[test]
932 fn varint_len_eight_bytes() {
933 assert_eq!(varint_len(0xC0), 8);
934 assert_eq!(varint_len(0xFF), 8);
935 }
936
937 #[test]
938 fn client_config_alpn_quic_draft15() {
939 let config = ClientConfig {
940 draft: DraftVersion::Draft15,
941 transport: TransportType::Quic,
942 skip_cert_verification: false,
943 ca_certs: Vec::new(),
944 setup_parameters: Vec::new(),
945 };
946 assert_eq!(config.alpn(), vec![b"moqt-15".to_vec()]);
947 }
948
949 #[test]
950 fn client_config_alpn_webtransport() {
951 let config = ClientConfig {
952 draft: DraftVersion::Draft15,
953 transport: TransportType::WebTransport { url: "https://example.com".to_string() },
954 skip_cert_verification: false,
955 ca_certs: Vec::new(),
956 setup_parameters: Vec::new(),
957 };
958 assert_eq!(config.alpn(), vec![b"h3".to_vec()]);
959 }
960
961 #[test]
962 fn moqt_alpn_value() {
963 assert_eq!(MOQT_ALPN, b"moq-00");
964 }
965
966 #[test]
967 fn transport_type_debug() {
968 let quic = TransportType::Quic;
969 assert!(format!("{quic:?}").contains("Quic"));
970
971 let wt = TransportType::WebTransport { url: "https://example.com".to_string() };
972 assert!(format!("{wt:?}").contains("WebTransport"));
973 }
974}