1use crate::async_carrier::{self, AsyncCommandSender, DemandBatcher};
10use datum::{Flow, Keep, NotUsed, Sink, Source, StreamCompletion, StreamError, StreamResult};
11pub use quinn::{self, crypto, rustls};
12use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
13use std::sync::{Arc, Mutex, mpsc as std_mpsc};
14use tokio::net::ToSocketAddrs;
15use tokio::runtime::Handle;
16use tokio::sync::{mpsc, watch};
17use tokio::task::JoinHandle;
18
19pub const DEFAULT_CHUNK_SIZE: usize = 8192;
21
22const DEFAULT_RECEIVE_BUFFER: usize = 64;
23
24#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
26pub struct QuicCarrierDiagnosticCounts {
27 pub handshake_failures: u64,
28 pub accept_bi_failures: u64,
29}
30
31#[derive(Clone, Default)]
33pub struct QuicCarrierDiagnostics {
34 counts: Arc<Mutex<QuicCarrierDiagnosticCounts>>,
35}
36
37impl QuicCarrierDiagnostics {
38 #[must_use]
39 pub fn new() -> Self {
40 Self::default()
41 }
42
43 #[must_use]
44 pub fn snapshot(&self) -> QuicCarrierDiagnosticCounts {
45 *self
46 .counts
47 .lock()
48 .unwrap_or_else(|poison| poison.into_inner())
49 }
50
51 fn record_handshake_failure(&self) {
52 let mut counts = self
53 .counts
54 .lock()
55 .unwrap_or_else(|poison| poison.into_inner());
56 counts.handshake_failures = counts.handshake_failures.saturating_add(1);
57 }
58
59 fn record_accept_bi_failure(&self) {
60 let mut counts = self
61 .counts
62 .lock()
63 .unwrap_or_else(|poison| poison.into_inner());
64 counts.accept_bi_failures = counts.accept_bi_failures.saturating_add(1);
65 }
66}
67
68pub type QuicByteSource = Source<Vec<u8>, NotUsed>;
74
75pub type QuicByteSink = Sink<Vec<u8>, StreamCompletion<NotUsed>>;
80
81enum DemandResponse<T> {
82 Item(T),
83 Complete,
84 Error(StreamError),
85}
86
87struct ReadResource {
88 receiver: std_mpsc::Receiver<DemandResponse<Vec<u8>>>,
89 carrier: QuicCarrier,
90 demand: DemandBatcher,
91 pending: Option<DemandResponse<Vec<u8>>>,
92}
93
94impl Drop for ReadResource {
95 fn drop(&mut self) {
96 self.carrier.close_read();
97 }
98}
99
100enum QuicCarrierCommand {
101 Demand(usize),
102 SendOne(Vec<u8>),
103 SendBatch(Vec<Vec<u8>>),
104 CloseRead,
105 CloseWrite {
106 ack: std_mpsc::Sender<StreamResult<()>>,
107 },
108}
109
110#[derive(Clone)]
111struct QuicCarrier {
112 inner: Arc<QuicCarrierInner>,
113}
114
115struct QuicCarrierInner {
116 commands: AsyncCommandSender<QuicCarrierCommand>,
117 send_errors: Mutex<std_mpsc::Receiver<StreamError>>,
118 task: Mutex<Option<JoinHandle<()>>>,
119}
120
121impl Drop for QuicCarrierInner {
122 fn drop(&mut self) {
123 if let Some(task) = self
124 .task
125 .lock()
126 .unwrap_or_else(|poison| poison.into_inner())
127 .take()
128 {
129 task.abort();
130 }
131 }
132}
133
134impl QuicCarrier {
135 fn close_read(&self) {
136 let _ = self.inner.commands.try_send(QuicCarrierCommand::CloseRead);
137 }
138
139 fn request_demand(&self, demand: usize) -> StreamResult<()> {
140 self.inner
141 .commands
142 .send_or_blocking(QuicCarrierCommand::Demand(demand))
143 }
144
145 fn send_items(&self, items: Vec<Vec<u8>>) -> StreamResult<()> {
146 self.check_send_error()?;
147 self.inner
148 .commands
149 .send_or_blocking(QuicCarrierCommand::SendBatch(items))
150 .map_err(|error| StreamError::Failed(format!("QUIC send batch failed: {error:?}")))
151 }
152
153 fn send_one(&self, item: Vec<u8>) -> StreamResult<()> {
154 self.check_send_error()?;
155 self.inner
156 .commands
157 .send_or_blocking(QuicCarrierCommand::SendOne(item))
158 .map_err(|error| StreamError::Failed(format!("QUIC send failed: {error:?}")))
159 }
160
161 fn close_write(&self) -> StreamResult<()> {
162 self.check_send_error()?;
163 let (ack_sender, ack_receiver) = std_mpsc::channel();
164 if self
165 .inner
166 .commands
167 .send_or_blocking(QuicCarrierCommand::CloseWrite { ack: ack_sender })
168 .is_err()
169 {
170 return Ok(());
171 }
172 match ack_receiver.recv() {
173 Ok(result) => result,
174 Err(_) => Err(abrupt_termination()),
175 }?;
176 self.check_send_error()
177 }
178
179 fn check_send_error(&self) -> StreamResult<()> {
180 match self
181 .inner
182 .send_errors
183 .lock()
184 .expect("QUIC carrier send error receiver poisoned")
185 .try_recv()
186 {
187 Ok(error) => Err(error),
188 Err(std_mpsc::TryRecvError::Empty) | Err(std_mpsc::TryRecvError::Disconnected) => {
189 Ok(())
190 }
191 }
192 }
193}
194
195struct SendResource {
196 carrier: QuicCarrier,
197 pending: Vec<Vec<u8>>,
198 batch_size: usize,
199}
200
201#[derive(Clone, Copy)]
202struct QuicReadConfig {
203 chunk_size: usize,
204 emit_available: bool,
205}
206
207struct BindResource {
208 demands: mpsc::Sender<std_mpsc::Sender<DemandResponse<QuicIncomingConnection>>>,
209 cancel: watch::Sender<bool>,
210 task: JoinHandle<()>,
211}
212
213impl Drop for BindResource {
214 fn drop(&mut self) {
215 let _ = self.cancel.send(true);
216 self.task.abort();
217 }
218}
219
220struct AcceptBiResource {
221 demands: mpsc::Sender<std_mpsc::Sender<DemandResponse<QuicBidirectionalStream>>>,
222 cancel: watch::Sender<bool>,
223 task: JoinHandle<()>,
224}
225
226impl Drop for AcceptBiResource {
227 fn drop(&mut self) {
228 let _ = self.cancel.send(true);
229 self.task.abort();
230 }
231}
232
233fn quic_error(error: impl std::fmt::Display) -> StreamError {
234 StreamError::Failed(error.to_string())
235}
236
237fn io_error(error: std::io::Error) -> StreamError {
238 StreamError::Failed(error.to_string())
239}
240
241fn abrupt_termination() -> StreamError {
242 StreamError::AbruptTermination
243}
244
245fn close_code() -> quinn::VarInt {
246 quinn::VarInt::from_u32(0)
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq)]
251pub struct QuicBinding {
252 pub local_addr: SocketAddr,
253}
254
255impl QuicBinding {
256 #[must_use]
258 pub fn local_addr(&self) -> SocketAddr {
259 self.local_addr
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub struct QuicStream {
266 pub id: quinn::StreamId,
267}
268
269impl QuicStream {
270 #[must_use]
272 pub fn id(&self) -> quinn::StreamId {
273 self.id
274 }
275}
276
277#[derive(Debug, Clone)]
279pub struct QuicConnection {
280 endpoint: quinn::Endpoint,
281 connection: quinn::Connection,
282 handle: Handle,
283 local_addr: SocketAddr,
284 remote_addr: SocketAddr,
285 chunk_size: usize,
286}
287
288impl QuicConnection {
289 #[must_use]
291 pub fn local_addr(&self) -> SocketAddr {
292 self.local_addr
293 }
294
295 #[must_use]
297 pub fn remote_addr(&self) -> SocketAddr {
298 self.remote_addr
299 }
300
301 #[must_use]
303 pub fn chunk_size(&self) -> usize {
304 self.chunk_size
305 }
306
307 #[must_use]
309 pub fn quinn_connection(&self) -> &quinn::Connection {
310 &self.connection
311 }
312
313 #[must_use]
315 pub fn quinn_endpoint(&self) -> &quinn::Endpoint {
316 &self.endpoint
317 }
318
319 #[must_use]
326 pub fn open_bi(
327 &self,
328 chunk_size: usize,
329 ) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<QuicStream>> {
330 assert!(chunk_size > 0, "chunk size must be greater than zero");
331 let connection = self.connection.clone();
332 let handle = self.handle.clone();
333 Flow::future_flow(move || {
334 let connection = connection.clone();
335 let handle = handle.clone();
336 async move {
337 let (send, recv) = connection.open_bi().await.map_err(quic_error)?;
338 Ok(quic_bi_stream_from_halves(send, recv, handle, chunk_size, false).into_flow())
339 }
340 })
341 }
342
343 #[must_use]
345 pub fn open_bi_default(&self) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<QuicStream>> {
346 self.open_bi(self.chunk_size)
347 }
348
349 #[must_use]
355 pub fn open_bi_stream(
356 &self,
357 chunk_size: usize,
358 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
359 assert!(chunk_size > 0, "chunk size must be greater than zero");
360 let connection = self.connection.clone();
361 let handle = self.handle.clone();
362 Source::lazy_future_source(move || {
363 let connection = connection.clone();
364 let handle = handle.clone();
365 async move {
366 let (send, recv) = connection.open_bi().await.map_err(quic_error)?;
367 let stream = quic_bi_stream_from_halves(send, recv, handle, chunk_size, false);
368 let metadata = stream.stream();
369 let stream = Arc::new(Mutex::new(Some(stream)));
370 Ok(Source::unfold_resource(
371 {
372 let stream = Arc::clone(&stream);
373 move || {
374 stream
375 .lock()
376 .expect("single-use QUIC bidi stream poisoned")
377 .take()
378 .map(Some)
379 .ok_or_else(|| {
380 StreamError::Failed(
381 "QUIC bidi stream already materialized".into(),
382 )
383 })
384 }
385 },
386 |stream| Ok(stream.take()),
387 |_stream| Ok(()),
388 )
389 .map_materialized_value(move |_| metadata))
390 }
391 })
392 }
393
394 #[must_use]
396 pub fn open_bi_stream_default(
397 &self,
398 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
399 self.open_bi_stream(self.chunk_size)
400 }
401
402 #[must_use]
409 pub fn open_bi_stream_available(
410 &self,
411 chunk_size: usize,
412 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
413 assert!(chunk_size > 0, "chunk size must be greater than zero");
414 let connection = self.connection.clone();
415 let handle = self.handle.clone();
416 Source::lazy_future_source(move || {
417 let connection = connection.clone();
418 let handle = handle.clone();
419 async move {
420 let (send, recv) = connection.open_bi().await.map_err(quic_error)?;
421 let stream = quic_bi_stream_from_halves(send, recv, handle, chunk_size, true);
422 let metadata = stream.stream();
423 let stream = Arc::new(Mutex::new(Some(stream)));
424 Ok(Source::unfold_resource(
425 {
426 let stream = Arc::clone(&stream);
427 move || {
428 stream
429 .lock()
430 .expect("single-use QUIC bidi stream poisoned")
431 .take()
432 .map(Some)
433 .ok_or_else(|| {
434 StreamError::Failed(
435 "QUIC bidi stream already materialized".into(),
436 )
437 })
438 }
439 },
440 |stream| Ok(stream.take()),
441 |_stream| Ok(()),
442 )
443 .map_materialized_value(move |_| metadata))
444 }
445 })
446 }
447
448 #[must_use]
454 pub fn accept_bi(&self, chunk_size: usize) -> Source<QuicBidirectionalStream, QuicConnection> {
455 self.accept_bi_optional_diagnostics(chunk_size, false, None)
456 }
457
458 #[must_use]
460 pub fn accept_bi_with_diagnostics(
461 &self,
462 chunk_size: usize,
463 diagnostics: QuicCarrierDiagnostics,
464 ) -> Source<QuicBidirectionalStream, QuicConnection> {
465 self.accept_bi_optional_diagnostics(chunk_size, false, Some(diagnostics))
466 }
467
468 fn accept_bi_optional_diagnostics(
469 &self,
470 chunk_size: usize,
471 emit_available: bool,
472 diagnostics: Option<QuicCarrierDiagnostics>,
473 ) -> Source<QuicBidirectionalStream, QuicConnection> {
474 assert!(chunk_size > 0, "chunk size must be greater than zero");
475 let connection = self.clone();
476 Source::unfold_resource(
477 {
478 let connection = connection.clone();
479 let diagnostics = diagnostics.clone();
480 move || {
481 let handle = connection.handle.clone();
482 let (demand_sender, demand_receiver) = mpsc::channel(1);
483 let (cancel_sender, cancel_receiver) = watch::channel(false);
484 let task = handle.spawn(run_accept_bi_task(
485 connection.connection.clone(),
486 chunk_size,
487 emit_available,
488 handle.clone(),
489 diagnostics.clone(),
490 demand_receiver,
491 cancel_receiver,
492 ));
493 Ok(AcceptBiResource {
494 demands: demand_sender,
495 cancel: cancel_sender,
496 task,
497 })
498 }
499 },
500 receive_demand_response,
501 close_accept_bi_resource,
502 )
503 .map_materialized_value(move |_| connection.clone())
504 }
505
506 #[must_use]
509 pub fn accept_bi_default(&self) -> Source<QuicBidirectionalStream, QuicConnection> {
510 self.accept_bi(self.chunk_size)
511 }
512
513 #[must_use]
518 pub fn accept_bi_available(
519 &self,
520 chunk_size: usize,
521 ) -> Source<QuicBidirectionalStream, QuicConnection> {
522 self.accept_bi_optional_diagnostics(chunk_size, true, None)
523 }
524
525 #[must_use]
527 pub fn accept_bi_available_with_diagnostics(
528 &self,
529 chunk_size: usize,
530 diagnostics: QuicCarrierDiagnostics,
531 ) -> Source<QuicBidirectionalStream, QuicConnection> {
532 self.accept_bi_optional_diagnostics(chunk_size, true, Some(diagnostics))
533 }
534
535 pub fn close(&self, reason: &[u8]) {
537 self.connection.close(close_code(), reason);
538 }
539}
540
541#[derive(Debug, Clone)]
543pub struct QuicIncomingConnection {
544 connection: QuicConnection,
545}
546
547impl QuicIncomingConnection {
548 #[must_use]
550 pub fn local_addr(&self) -> SocketAddr {
551 self.connection.local_addr()
552 }
553
554 #[must_use]
556 pub fn remote_addr(&self) -> SocketAddr {
557 self.connection.remote_addr()
558 }
559
560 #[must_use]
562 pub fn connection(&self) -> QuicConnection {
563 self.connection.clone()
564 }
565
566 #[must_use]
568 pub fn into_connection(self) -> QuicConnection {
569 self.connection
570 }
571
572 #[must_use]
574 pub fn open_bi(
575 &self,
576 chunk_size: usize,
577 ) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<QuicStream>> {
578 self.connection.open_bi(chunk_size)
579 }
580
581 #[must_use]
583 pub fn open_bi_default(&self) -> Flow<Vec<u8>, Vec<u8>, StreamCompletion<QuicStream>> {
584 self.connection.open_bi_default()
585 }
586
587 #[must_use]
589 pub fn open_bi_stream(
590 &self,
591 chunk_size: usize,
592 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
593 self.connection.open_bi_stream(chunk_size)
594 }
595
596 #[must_use]
598 pub fn open_bi_stream_default(
599 &self,
600 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
601 self.connection.open_bi_stream_default()
602 }
603
604 #[must_use]
606 pub fn open_bi_stream_available(
607 &self,
608 chunk_size: usize,
609 ) -> Source<QuicBidirectionalStream, StreamCompletion<QuicStream>> {
610 self.connection.open_bi_stream_available(chunk_size)
611 }
612
613 #[must_use]
615 pub fn accept_bi(&self, chunk_size: usize) -> Source<QuicBidirectionalStream, QuicConnection> {
616 self.connection.accept_bi(chunk_size)
617 }
618
619 #[must_use]
621 pub fn accept_bi_with_diagnostics(
622 &self,
623 chunk_size: usize,
624 diagnostics: QuicCarrierDiagnostics,
625 ) -> Source<QuicBidirectionalStream, QuicConnection> {
626 self.connection
627 .accept_bi_with_diagnostics(chunk_size, diagnostics)
628 }
629
630 #[must_use]
632 pub fn accept_bi_default(&self) -> Source<QuicBidirectionalStream, QuicConnection> {
633 self.connection.accept_bi_default()
634 }
635
636 #[must_use]
638 pub fn accept_bi_available(
639 &self,
640 chunk_size: usize,
641 ) -> Source<QuicBidirectionalStream, QuicConnection> {
642 self.connection.accept_bi_available(chunk_size)
643 }
644
645 #[must_use]
647 pub fn accept_bi_available_with_diagnostics(
648 &self,
649 chunk_size: usize,
650 diagnostics: QuicCarrierDiagnostics,
651 ) -> Source<QuicBidirectionalStream, QuicConnection> {
652 self.connection
653 .accept_bi_available_with_diagnostics(chunk_size, diagnostics)
654 }
655}
656
657pub struct QuicBidirectionalStream {
659 stream: QuicStream,
660 send: quinn::SendStream,
661 recv: quinn::RecvStream,
662 handle: Handle,
663 chunk_size: usize,
664 emit_available: bool,
665}
666
667impl QuicBidirectionalStream {
668 #[must_use]
670 pub fn stream(&self) -> QuicStream {
671 self.stream
672 }
673
674 #[must_use]
676 pub fn into_parts(self) -> (QuicByteSource, QuicByteSink) {
677 let Self {
678 send,
679 recv,
680 handle,
681 chunk_size,
682 emit_available,
683 ..
684 } = self;
685 single_use_quic_halves(send, recv, handle, chunk_size, emit_available)
686 }
687
688 #[must_use]
690 pub fn into_flow(self) -> Flow<Vec<u8>, Vec<u8>, QuicStream> {
691 let stream = self.stream;
692 let (source, sink) = self.into_parts();
693 Flow::from_sink_and_source(sink, source).map_materialized_value(move |_| stream)
694 }
695
696 pub(crate) fn into_stream_ref_parts(
697 self,
698 ) -> (quinn::RecvStream, quinn::SendStream, Handle, usize, bool) {
699 (
700 self.recv,
701 self.send,
702 self.handle,
703 self.chunk_size,
704 self.emit_available,
705 )
706 }
707}
708
709pub struct TokioQuic;
711
712pub type Quic = TokioQuic;
714
715impl TokioQuic {
716 #[must_use]
722 pub fn bind<A>(
723 addr: A,
724 server_config: quinn::ServerConfig,
725 chunk_size: usize,
726 ) -> Source<QuicIncomingConnection, StreamCompletion<QuicBinding>>
727 where
728 A: ToSocketAddrs + Clone + Send + Sync + 'static,
729 {
730 Self::bind_optional_diagnostics(addr, server_config, chunk_size, None)
731 }
732
733 #[must_use]
735 pub fn bind_with_diagnostics<A>(
736 addr: A,
737 server_config: quinn::ServerConfig,
738 chunk_size: usize,
739 diagnostics: QuicCarrierDiagnostics,
740 ) -> Source<QuicIncomingConnection, StreamCompletion<QuicBinding>>
741 where
742 A: ToSocketAddrs + Clone + Send + Sync + 'static,
743 {
744 Self::bind_optional_diagnostics(addr, server_config, chunk_size, Some(diagnostics))
745 }
746
747 fn bind_optional_diagnostics<A>(
748 addr: A,
749 server_config: quinn::ServerConfig,
750 chunk_size: usize,
751 diagnostics: Option<QuicCarrierDiagnostics>,
752 ) -> Source<QuicIncomingConnection, StreamCompletion<QuicBinding>>
753 where
754 A: ToSocketAddrs + Clone + Send + Sync + 'static,
755 {
756 assert!(chunk_size > 0, "chunk size must be greater than zero");
757 Source::lazy_future_source(move || {
758 let addr = addr.clone();
759 let server_config = server_config.clone();
760 let diagnostics = diagnostics.clone();
761 async move {
762 let handle = Handle::current();
763 let addr = resolve_addr(addr).await?;
764 let endpoint = quinn::Endpoint::server(server_config, addr).map_err(io_error)?;
765 let local_addr = endpoint.local_addr().map_err(io_error)?;
766 Ok(quic_bind_source(
767 endpoint,
768 local_addr,
769 handle,
770 chunk_size,
771 diagnostics,
772 ))
773 }
774 })
775 }
776
777 #[must_use]
779 pub fn bind_default<A>(
780 addr: A,
781 server_config: quinn::ServerConfig,
782 ) -> Source<QuicIncomingConnection, StreamCompletion<QuicBinding>>
783 where
784 A: ToSocketAddrs + Clone + Send + Sync + 'static,
785 {
786 Self::bind(addr, server_config, DEFAULT_CHUNK_SIZE)
787 }
788
789 #[must_use]
795 pub fn connect<A>(
796 addr: A,
797 server_name: impl Into<String>,
798 client_config: quinn::ClientConfig,
799 chunk_size: usize,
800 ) -> Source<QuicConnection, StreamCompletion<QuicConnection>>
801 where
802 A: ToSocketAddrs + Clone + Send + Sync + 'static,
803 {
804 assert!(chunk_size > 0, "chunk size must be greater than zero");
805 let server_name = server_name.into();
806 Source::lazy_future_source(move || {
807 let addr = addr.clone();
808 let server_name = server_name.clone();
809 let client_config = client_config.clone();
810 async move {
811 let remote_addr = resolve_addr(addr).await?;
812 let local_addr = client_bind_addr(remote_addr);
813 let mut endpoint = quinn::Endpoint::client(local_addr).map_err(io_error)?;
814 endpoint.set_default_client_config(client_config);
815 let connecting = endpoint
816 .connect(remote_addr, &server_name)
817 .map_err(quic_error)?;
818 let connection = connecting.await.map_err(quic_error)?;
819 let endpoint_local_addr = endpoint.local_addr().map_err(io_error)?;
820 let connection = QuicConnection {
821 local_addr: connection_local_addr(
822 &connection,
823 endpoint_local_addr,
824 remote_addr.ip(),
825 ),
826 remote_addr: connection.remote_address(),
827 endpoint,
828 connection,
829 handle: Handle::current(),
830 chunk_size,
831 };
832 let materialized = connection.clone();
833 Ok(
834 Source::single(connection)
835 .map_materialized_value(move |_| materialized.clone()),
836 )
837 }
838 })
839 }
840
841 #[must_use]
843 pub fn connect_default<A>(
844 addr: A,
845 server_name: impl Into<String>,
846 client_config: quinn::ClientConfig,
847 ) -> Source<QuicConnection, StreamCompletion<QuicConnection>>
848 where
849 A: ToSocketAddrs + Clone + Send + Sync + 'static,
850 {
851 Self::connect(addr, server_name, client_config, DEFAULT_CHUNK_SIZE)
852 }
853}
854
855async fn resolve_addr<A>(addr: A) -> StreamResult<SocketAddr>
856where
857 A: ToSocketAddrs,
858{
859 let mut addrs = tokio::net::lookup_host(addr).await.map_err(io_error)?;
860 addrs
861 .next()
862 .ok_or_else(|| StreamError::Failed("address resolved to no socket addresses".into()))
863}
864
865fn client_bind_addr(remote_addr: SocketAddr) -> SocketAddr {
866 if remote_addr.is_ipv6() {
867 SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
868 } else {
869 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
870 }
871}
872
873fn connection_local_addr(
874 connection: &quinn::Connection,
875 endpoint_addr: SocketAddr,
876 fallback_ip: IpAddr,
877) -> SocketAddr {
878 connection
879 .local_ip()
880 .map(|ip| SocketAddr::new(ip, endpoint_addr.port()))
881 .or_else(|| {
882 endpoint_addr
883 .ip()
884 .is_unspecified()
885 .then(|| SocketAddr::new(fallback_ip, endpoint_addr.port()))
886 })
887 .unwrap_or(endpoint_addr)
888}
889
890fn quic_bi_stream_from_halves(
891 send: quinn::SendStream,
892 recv: quinn::RecvStream,
893 handle: Handle,
894 chunk_size: usize,
895 emit_available: bool,
896) -> QuicBidirectionalStream {
897 let stream = QuicStream { id: send.id() };
898 QuicBidirectionalStream {
899 stream,
900 send,
901 recv,
902 handle,
903 chunk_size,
904 emit_available,
905 }
906}
907
908fn single_use_quic_halves(
909 send: quinn::SendStream,
910 recv: quinn::RecvStream,
911 handle: Handle,
912 chunk_size: usize,
913 emit_available: bool,
914) -> (QuicByteSource, QuicByteSink) {
915 let (carrier, receiver) = start_quic_carrier(
916 send,
917 recv,
918 handle,
919 chunk_size,
920 emit_available,
921 DEFAULT_RECEIVE_BUFFER,
922 );
923 let source =
924 single_use_quic_read_source_from_carrier(carrier.clone(), receiver, DEFAULT_RECEIVE_BUFFER);
925 let sink = single_use_quic_write_sink_from_carrier(carrier, 1);
926 (source, sink)
927}
928
929fn single_use_quic_read_source_from_carrier(
930 carrier: QuicCarrier,
931 receiver: std_mpsc::Receiver<DemandResponse<Vec<u8>>>,
932 receive_buffer: usize,
933) -> QuicByteSource {
934 let receiver = Arc::new(Mutex::new(Some(receiver)));
935 Source::unfold_resource(
936 {
937 let receiver = Arc::clone(&receiver);
938 move || {
939 let receiver = receiver
940 .lock()
941 .expect("single-use QUIC receiver poisoned")
942 .take()
943 .ok_or_else(|| {
944 StreamError::Failed("QUIC source already materialized".into())
945 })?;
946 let demand = DemandBatcher::new(receive_buffer);
947 let pending = match carrier.request_demand(demand.initial()) {
948 Ok(()) => None,
949 Err(error) => match receiver.try_recv() {
950 Ok(response) => Some(response),
951 Err(std_mpsc::TryRecvError::Empty) => return Err(error),
952 Err(std_mpsc::TryRecvError::Disconnected) => {
953 return Err(abrupt_termination());
954 }
955 },
956 };
957 Ok(ReadResource {
958 receiver,
959 carrier: carrier.clone(),
960 demand,
961 pending,
962 })
963 }
964 },
965 read_next_quic_chunk,
966 close_read_resource,
967 )
968}
969
970fn read_next_quic_chunk(resource: &mut ReadResource) -> StreamResult<Option<Vec<u8>>> {
971 let response = match resource.pending.take() {
972 Some(response) => response,
973 None => resource.receiver.recv().map_err(|_| abrupt_termination())?,
974 };
975 match response {
976 DemandResponse::Item(chunk) => {
977 if let Some(demand) = resource.demand.record_consumed() {
978 let _ = resource.carrier.request_demand(demand);
979 }
980 Ok(Some(chunk))
981 }
982 DemandResponse::Complete => Ok(None),
983 DemandResponse::Error(error) => Err(error),
984 }
985}
986
987fn close_read_resource(resource: ReadResource) -> StreamResult<()> {
988 resource.carrier.close_read();
989 Ok(())
990}
991
992fn start_quic_carrier(
993 send: quinn::SendStream,
994 recv: quinn::RecvStream,
995 handle: Handle,
996 chunk_size: usize,
997 emit_available: bool,
998 receive_buffer: usize,
999) -> (QuicCarrier, std_mpsc::Receiver<DemandResponse<Vec<u8>>>) {
1000 let command_capacity = async_carrier::DEFAULT_COMMAND_BUFFER.max(receive_buffer);
1001 let (commands, command_receiver) = async_carrier::command_channel(command_capacity, "QUIC");
1002 let (send_error_sender, send_error_receiver) = std_mpsc::channel();
1003 let (receive_sender, receive_receiver) =
1004 std_mpsc::sync_channel(receive_buffer.saturating_add(1));
1005 let command_keepalive = commands.clone();
1006 let read_config = QuicReadConfig {
1007 chunk_size,
1008 emit_available,
1009 };
1010 let task = handle.spawn(run_quic_carrier_task(
1011 send,
1012 recv,
1013 read_config,
1014 receive_sender,
1015 send_error_sender,
1016 command_keepalive,
1017 command_receiver,
1018 ));
1019 (
1020 QuicCarrier {
1021 inner: Arc::new(QuicCarrierInner {
1022 commands,
1023 send_errors: Mutex::new(send_error_receiver),
1024 task: Mutex::new(Some(task)),
1025 }),
1026 },
1027 receive_receiver,
1028 )
1029}
1030
1031async fn run_quic_carrier_task(
1032 mut send: quinn::SendStream,
1033 mut recv: quinn::RecvStream,
1034 read_config: QuicReadConfig,
1035 receive_sender: std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
1036 send_error_sender: std_mpsc::Sender<StreamError>,
1037 _command_keepalive: AsyncCommandSender<QuicCarrierCommand>,
1038 mut commands: mpsc::Receiver<QuicCarrierCommand>,
1039) {
1040 let mut buffer = vec![0_u8; read_config.chunk_size];
1041 let mut pending_tail = Vec::with_capacity(read_config.chunk_size);
1042 let mut requested = 0_usize;
1043 let mut read_open = true;
1044 let mut write_open = true;
1045
1046 loop {
1047 if !read_open && !write_open {
1048 return;
1049 }
1050
1051 if read_open && requested > 0 {
1052 tokio::select! {
1053 biased;
1054 command = commands.recv() => {
1055 let Some(command) = command else {
1056 return;
1057 };
1058 if !handle_quic_carrier_command(
1059 &mut send,
1060 command,
1061 &send_error_sender,
1062 &mut read_open,
1063 &mut write_open,
1064 &mut requested,
1065 ).await {
1066 return;
1067 }
1068 }
1069 read = recv.read(&mut buffer) => {
1070 match read {
1071 Ok(Some(read)) => {
1072 match queue_quic_read_chunks(
1073 &receive_sender,
1074 &send_error_sender,
1075 read_config.chunk_size,
1076 &mut pending_tail,
1077 &buffer[..read],
1078 read_config.emit_available,
1079 ) {
1080 QuicReadQueueResult::Queued(queued) => {
1081 requested = requested.saturating_sub(queued);
1082 }
1083 QuicReadQueueResult::Closed => {
1084 read_open = false;
1085 }
1086 QuicReadQueueResult::Failed => {
1087 return;
1088 }
1089 }
1090 }
1091 Ok(None) => {
1092 if !pending_tail.is_empty() {
1093 match try_send_quic_read_response(
1094 &receive_sender,
1095 DemandResponse::Item(std::mem::take(&mut pending_tail)),
1096 ) {
1097 QuicQueueOutcome::Queued => {
1098 requested = requested.saturating_sub(1);
1099 }
1100 QuicQueueOutcome::Closed => {
1101 read_open = false;
1102 continue;
1103 }
1104 QuicQueueOutcome::Full => {
1105 report_quic_read_error(
1106 &receive_sender,
1107 &send_error_sender,
1108 quic_receive_buffer_overflow(),
1109 );
1110 return;
1111 }
1112 }
1113 }
1114 match try_send_quic_read_response(
1115 &receive_sender,
1116 DemandResponse::Complete,
1117 ) {
1118 QuicQueueOutcome::Queued | QuicQueueOutcome::Closed => {
1119 read_open = false;
1120 }
1121 QuicQueueOutcome::Full => {
1122 report_quic_read_error(
1123 &receive_sender,
1124 &send_error_sender,
1125 quic_receive_buffer_overflow(),
1126 );
1127 return;
1128 }
1129 }
1130 }
1131 Err(error) => {
1132 report_quic_read_error(
1133 &receive_sender,
1134 &send_error_sender,
1135 quic_error(error),
1136 );
1137 return;
1138 }
1139 }
1140 }
1141 }
1142 } else {
1143 let Some(command) = commands.recv().await else {
1144 return;
1145 };
1146 if !handle_quic_carrier_command(
1147 &mut send,
1148 command,
1149 &send_error_sender,
1150 &mut read_open,
1151 &mut write_open,
1152 &mut requested,
1153 )
1154 .await
1155 {
1156 return;
1157 }
1158 }
1159 }
1160}
1161
1162async fn handle_quic_carrier_command(
1163 send: &mut quinn::SendStream,
1164 command: QuicCarrierCommand,
1165 send_error_sender: &std_mpsc::Sender<StreamError>,
1166 read_open: &mut bool,
1167 write_open: &mut bool,
1168 requested: &mut usize,
1169) -> bool {
1170 match command {
1171 QuicCarrierCommand::Demand(demand) => {
1172 *requested = requested.saturating_add(demand);
1173 true
1174 }
1175 QuicCarrierCommand::SendOne(chunk) => {
1176 if !*write_open {
1177 report_quic_write_error(
1178 send_error_sender,
1179 StreamError::Failed("QUIC write side is closed".to_owned()),
1180 );
1181 return *read_open;
1182 }
1183 if write_one_quic_chunk(send, send_error_sender, &chunk).await {
1184 true
1185 } else {
1186 *write_open = false;
1187 *read_open
1188 }
1189 }
1190 QuicCarrierCommand::SendBatch(chunks) => {
1191 if !*write_open {
1192 report_quic_write_error(
1193 send_error_sender,
1194 StreamError::Failed("QUIC write side is closed".to_owned()),
1195 );
1196 return *read_open;
1197 }
1198 for chunk in &chunks {
1199 if let Err(error) = send.write_all(chunk).await.map_err(quic_error) {
1200 report_quic_write_error(send_error_sender, error);
1201 *write_open = false;
1202 return *read_open;
1203 }
1204 }
1205 true
1206 }
1207 QuicCarrierCommand::CloseRead => {
1208 *read_open = false;
1209 true
1210 }
1211 QuicCarrierCommand::CloseWrite { ack } => {
1212 *write_open = false;
1213 let result = close_quic_writer(send).await;
1214 match result {
1215 Ok(()) => {
1216 let _ = ack.send(Ok(()));
1217 true
1218 }
1219 Err(error) => {
1220 report_quic_write_error(send_error_sender, error.clone());
1221 let _ = ack.send(Err(error));
1222 *read_open
1223 }
1224 }
1225 }
1226 }
1227}
1228
1229async fn write_one_quic_chunk(
1230 send: &mut quinn::SendStream,
1231 send_error_sender: &std_mpsc::Sender<StreamError>,
1232 chunk: &[u8],
1233) -> bool {
1234 if let Err(error) = send.write_all(chunk).await.map_err(quic_error) {
1235 report_quic_write_error(send_error_sender, error);
1236 return false;
1237 }
1238 true
1239}
1240
1241async fn close_quic_writer(send: &mut quinn::SendStream) -> StreamResult<()> {
1242 send.write_all(&[]).await.map_err(quic_error)?;
1243 send.finish().map_err(quic_error)
1244}
1245
1246enum QuicReadQueueResult {
1247 Queued(usize),
1248 Closed,
1249 Failed,
1250}
1251
1252enum QuicQueueOutcome {
1253 Queued,
1254 Full,
1255 Closed,
1256}
1257
1258fn queue_quic_read_chunks(
1259 sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
1260 send_error_sender: &std_mpsc::Sender<StreamError>,
1261 chunk_size: usize,
1262 pending_tail: &mut Vec<u8>,
1263 read_buffer: &[u8],
1264 emit_available: bool,
1265) -> QuicReadQueueResult {
1266 let mut offset = 0;
1267 let mut queued = 0_usize;
1268 if !pending_tail.is_empty() {
1269 let needed = chunk_size - pending_tail.len();
1270 let take = needed.min(read_buffer.len());
1271 pending_tail.extend_from_slice(&read_buffer[..take]);
1272 offset += take;
1273 if pending_tail.len() == chunk_size {
1274 match try_send_quic_read_response(
1275 sender,
1276 DemandResponse::Item(std::mem::take(pending_tail)),
1277 ) {
1278 QuicQueueOutcome::Queued => queued += 1,
1279 QuicQueueOutcome::Closed => return QuicReadQueueResult::Closed,
1280 QuicQueueOutcome::Full => {
1281 report_quic_read_error(
1282 sender,
1283 send_error_sender,
1284 quic_receive_buffer_overflow(),
1285 );
1286 return QuicReadQueueResult::Failed;
1287 }
1288 }
1289 }
1290 }
1291
1292 while offset + chunk_size <= read_buffer.len() {
1293 let next = offset + chunk_size;
1294 match try_send_quic_read_response(
1295 sender,
1296 DemandResponse::Item(read_buffer[offset..next].to_vec()),
1297 ) {
1298 QuicQueueOutcome::Queued => queued += 1,
1299 QuicQueueOutcome::Closed => return QuicReadQueueResult::Closed,
1300 QuicQueueOutcome::Full => {
1301 report_quic_read_error(sender, send_error_sender, quic_receive_buffer_overflow());
1302 return QuicReadQueueResult::Failed;
1303 }
1304 }
1305 offset = next;
1306 }
1307
1308 if offset < read_buffer.len() {
1309 pending_tail.extend_from_slice(&read_buffer[offset..]);
1310 }
1311 if emit_available && !pending_tail.is_empty() {
1312 match try_send_quic_read_response(
1313 sender,
1314 DemandResponse::Item(std::mem::take(pending_tail)),
1315 ) {
1316 QuicQueueOutcome::Queued => queued += 1,
1317 QuicQueueOutcome::Closed => return QuicReadQueueResult::Closed,
1318 QuicQueueOutcome::Full => {
1319 report_quic_read_error(sender, send_error_sender, quic_receive_buffer_overflow());
1320 return QuicReadQueueResult::Failed;
1321 }
1322 }
1323 }
1324 QuicReadQueueResult::Queued(queued)
1325}
1326
1327fn try_send_quic_read_response(
1328 sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
1329 item: DemandResponse<Vec<u8>>,
1330) -> QuicQueueOutcome {
1331 match sender.try_send(item) {
1332 Ok(()) => QuicQueueOutcome::Queued,
1333 Err(std_mpsc::TrySendError::Full(_)) => QuicQueueOutcome::Full,
1334 Err(std_mpsc::TrySendError::Disconnected(_)) => QuicQueueOutcome::Closed,
1335 }
1336}
1337
1338fn report_quic_read_error(
1339 receive_sender: &std_mpsc::SyncSender<DemandResponse<Vec<u8>>>,
1340 send_error_sender: &std_mpsc::Sender<StreamError>,
1341 error: StreamError,
1342) {
1343 let _ = send_error_sender.send(error.clone());
1344 let _ = receive_sender.try_send(DemandResponse::Error(error));
1345}
1346
1347fn report_quic_write_error(send_error_sender: &std_mpsc::Sender<StreamError>, error: StreamError) {
1348 let _ = send_error_sender.send(error);
1349}
1350
1351fn quic_receive_buffer_overflow() -> StreamError {
1352 StreamError::Failed("QUIC receive buffer filled without downstream demand".to_owned())
1353}
1354
1355fn single_use_quic_write_sink_from_carrier(
1356 carrier: QuicCarrier,
1357 batch_size: usize,
1358) -> QuicByteSink {
1359 let carrier = Arc::new(Mutex::new(Some(carrier)));
1360 Flow::<Vec<u8>, Vec<u8>>::identity()
1361 .map_with_resource(
1362 {
1363 let carrier = Arc::clone(&carrier);
1364 move || {
1365 let carrier = carrier
1366 .lock()
1367 .expect("single-use QUIC carrier poisoned")
1368 .take()
1369 .ok_or_else(|| {
1370 StreamError::Failed("QUIC sink already materialized".into())
1371 })?;
1372 Ok(SendResource {
1373 carrier,
1374 pending: Vec::with_capacity(batch_size),
1375 batch_size,
1376 })
1377 }
1378 },
1379 |resource, chunk| {
1380 send_quic_chunk(resource, chunk)?;
1381 Ok(NotUsed)
1382 },
1383 close_quic_send_resource,
1384 )
1385 .to_mat(Sink::ignore(), Keep::right)
1386}
1387
1388fn close_quic_send_resource(mut resource: SendResource) -> StreamResult<Option<NotUsed>> {
1389 flush_quic_send_resource(&mut resource)?;
1390 resource.carrier.close_write()?;
1391 Ok(None)
1392}
1393
1394fn send_quic_chunk(resource: &mut SendResource, chunk: Vec<u8>) -> StreamResult<()> {
1395 if resource.batch_size <= 1 {
1396 return resource.carrier.send_one(chunk);
1397 }
1398 resource.pending.push(chunk);
1399 if resource.pending.len() >= resource.batch_size {
1400 flush_quic_send_resource(resource)?;
1401 }
1402 Ok(())
1403}
1404
1405fn flush_quic_send_resource(resource: &mut SendResource) -> StreamResult<()> {
1406 if resource.pending.is_empty() {
1407 return resource.carrier.check_send_error();
1408 }
1409 let pending = std::mem::take(&mut resource.pending);
1410 resource.carrier.send_items(pending)
1411}
1412
1413fn quic_bind_source(
1414 endpoint: quinn::Endpoint,
1415 local_addr: SocketAddr,
1416 handle: Handle,
1417 chunk_size: usize,
1418 diagnostics: Option<QuicCarrierDiagnostics>,
1419) -> Source<QuicIncomingConnection, QuicBinding> {
1420 let endpoint = Arc::new(Mutex::new(Some(endpoint)));
1421 Source::unfold_resource(
1422 {
1423 let endpoint = Arc::clone(&endpoint);
1424 let handle = handle.clone();
1425 move || {
1426 let endpoint = endpoint
1427 .lock()
1428 .expect("single-use QUIC endpoint poisoned")
1429 .take()
1430 .ok_or_else(|| {
1431 StreamError::Failed("QUIC endpoint already materialized".into())
1432 })?;
1433 let (demand_sender, demand_receiver) = mpsc::channel(1);
1434 let (cancel_sender, cancel_receiver) = watch::channel(false);
1435 let task = handle.spawn(run_quic_bind_task(
1436 endpoint,
1437 local_addr,
1438 chunk_size,
1439 handle.clone(),
1440 diagnostics.clone(),
1441 demand_receiver,
1442 cancel_receiver,
1443 ));
1444 Ok(BindResource {
1445 demands: demand_sender,
1446 cancel: cancel_sender,
1447 task,
1448 })
1449 }
1450 },
1451 receive_demand_response,
1452 close_bind_resource,
1453 )
1454 .map_materialized_value(move |_| QuicBinding { local_addr })
1455}
1456
1457fn receive_demand_response<T>(resource: &mut impl DemandResource<T>) -> StreamResult<Option<T>>
1458where
1459 T: Send + 'static,
1460{
1461 let (reply_sender, reply_receiver) = std_mpsc::channel();
1462 resource
1463 .demands()
1464 .blocking_send(reply_sender)
1465 .map_err(|_| abrupt_termination())?;
1466 match reply_receiver.recv() {
1467 Ok(DemandResponse::Item(item)) => Ok(Some(item)),
1468 Ok(DemandResponse::Complete) => Ok(None),
1469 Ok(DemandResponse::Error(error)) => Err(error),
1470 Err(_) => Err(abrupt_termination()),
1471 }
1472}
1473
1474trait DemandResource<T>
1475where
1476 T: Send + 'static,
1477{
1478 fn demands(&self) -> &mpsc::Sender<std_mpsc::Sender<DemandResponse<T>>>;
1479}
1480
1481impl DemandResource<QuicIncomingConnection> for BindResource {
1482 fn demands(&self) -> &mpsc::Sender<std_mpsc::Sender<DemandResponse<QuicIncomingConnection>>> {
1483 &self.demands
1484 }
1485}
1486
1487impl DemandResource<QuicBidirectionalStream> for AcceptBiResource {
1488 fn demands(&self) -> &mpsc::Sender<std_mpsc::Sender<DemandResponse<QuicBidirectionalStream>>> {
1489 &self.demands
1490 }
1491}
1492
1493fn close_bind_resource(resource: BindResource) -> StreamResult<()> {
1494 let _ = resource.cancel.send(true);
1495 resource.task.abort();
1496 Ok(())
1497}
1498
1499fn close_accept_bi_resource(resource: AcceptBiResource) -> StreamResult<()> {
1500 let _ = resource.cancel.send(true);
1501 resource.task.abort();
1502 Ok(())
1503}
1504
1505async fn run_quic_bind_task(
1506 endpoint: quinn::Endpoint,
1507 local_addr: SocketAddr,
1508 chunk_size: usize,
1509 handle: Handle,
1510 diagnostics: Option<QuicCarrierDiagnostics>,
1511 mut demands: mpsc::Receiver<std_mpsc::Sender<DemandResponse<QuicIncomingConnection>>>,
1512 mut cancel: watch::Receiver<bool>,
1513) {
1514 loop {
1515 let reply = tokio::select! {
1516 demand = demands.recv() => match demand {
1517 Some(reply) => reply,
1518 None => return,
1519 },
1520 changed = cancel.changed() => {
1521 let _ = changed;
1522 return;
1523 }
1524 };
1525
1526 loop {
1527 let incoming = tokio::select! {
1528 incoming = endpoint.accept() => incoming,
1529 changed = cancel.changed() => {
1530 let _ = changed;
1531 return;
1532 }
1533 };
1534
1535 let Some(incoming) = incoming else {
1536 let _ = reply.send(DemandResponse::Complete);
1537 return;
1538 };
1539
1540 let connected = tokio::select! {
1541 connected = incoming => connected,
1542 changed = cancel.changed() => {
1543 let _ = changed;
1544 return;
1545 }
1546 };
1547
1548 match connected {
1549 Ok(connection) => {
1550 let incoming = QuicIncomingConnection {
1551 connection: QuicConnection {
1552 endpoint: endpoint.clone(),
1553 local_addr: connection_local_addr(
1554 &connection,
1555 local_addr,
1556 local_addr.ip(),
1557 ),
1558 remote_addr: connection.remote_address(),
1559 connection,
1560 handle: handle.clone(),
1561 chunk_size,
1562 },
1563 };
1564 if reply.send(DemandResponse::Item(incoming)).is_err() {
1565 return;
1566 }
1567 break;
1568 }
1569 Err(error) => {
1570 if let Some(diagnostics) = &diagnostics {
1571 diagnostics.record_handshake_failure();
1572 }
1573 tracing::warn!(
1574 local_addr = %local_addr,
1575 error = %error,
1576 "QUIC connection handshake failed; continuing listener"
1577 );
1578 continue;
1579 }
1580 }
1581 }
1582 }
1583}
1584
1585async fn run_accept_bi_task(
1586 connection: quinn::Connection,
1587 chunk_size: usize,
1588 emit_available: bool,
1589 handle: Handle,
1590 diagnostics: Option<QuicCarrierDiagnostics>,
1591 mut demands: mpsc::Receiver<std_mpsc::Sender<DemandResponse<QuicBidirectionalStream>>>,
1592 mut cancel: watch::Receiver<bool>,
1593) {
1594 loop {
1595 let reply = tokio::select! {
1596 demand = demands.recv() => match demand {
1597 Some(reply) => reply,
1598 None => return,
1599 },
1600 changed = cancel.changed() => {
1601 let _ = changed;
1602 return;
1603 }
1604 };
1605
1606 let accepted = tokio::select! {
1607 accepted = connection.accept_bi() => accepted,
1608 changed = cancel.changed() => {
1609 let _ = changed;
1610 return;
1611 }
1612 };
1613
1614 match accepted {
1615 Ok((send, recv)) => {
1616 let stream = quic_bi_stream_from_halves(
1617 send,
1618 recv,
1619 handle.clone(),
1620 chunk_size,
1621 emit_available,
1622 );
1623 if reply.send(DemandResponse::Item(stream)).is_err() {
1624 return;
1625 }
1626 }
1627 Err(error) => {
1628 if let Some(diagnostics) = &diagnostics {
1629 diagnostics.record_accept_bi_failure();
1630 }
1631 tracing::warn!(
1632 remote_addr = %connection.remote_address(),
1633 error = %error,
1634 "QUIC accept_bi failed; completing stream accept source"
1635 );
1636 let _ = reply.send(DemandResponse::Complete);
1637 return;
1638 }
1639 }
1640 }
1641}