1use bytes::Bytes;
2use snafu::ResultExt;
3use std::future::Future;
4use std::pin::Pin;
5use std::time::Duration;
6use tokio::io::{AsyncReadExt, AsyncWriteExt};
7use tokio::time::Instant;
8
9use super::{
10 CodecMessageReader, CodecMessageWriter, MessageReader, MessageWriter, NormalMessageReader,
11 NormalMessageWriter,
12};
13use crate::buffer::{BufferReader, BufferedReader};
14use crate::data::DataCodec;
15use pb_mapper_core::checksum::AesKeyType;
16use pb_mapper_core::codec::{Decryptor, Encryptor};
17use pb_mapper_core::config::duration_from_env;
18use pb_mapper_core::error::{FwdNetworkWriteWithNormalSnafu, Result};
19use uni_stream::stream::{StreamSplit, TcpStreamImpl, UdpStreamImpl};
20use uni_stream::udp::{UdpStreamReadHalf, UdpStreamWriteHalf};
21
22pub trait ForwardReader {
23 async fn read(&mut self) -> Result<&'_ [u8]>;
24}
25
26pub trait ForwardWriter {
27 async fn write(&mut self, src: &[u8]) -> Result<()>;
28
29 async fn shutdown(&mut self);
31}
32
33pub trait DatagramReader {
34 async fn recv(&mut self) -> Result<Bytes>;
35}
36
37pub trait DatagramWriter {
38 async fn send(&mut self, src: &[u8]) -> Result<()>;
39}
40
41const DEFAULT_TUNNEL_IDLE_TIMEOUT: Duration = Duration::from_secs(60 * 60);
42const DEFAULT_HALF_CLOSE_IDLE_TIMEOUT: Duration = Duration::from_secs(60);
43const PB_MAPPER_TUNNEL_IDLE_TIMEOUT: &str = "PB_MAPPER_TUNNEL_IDLE_TIMEOUT";
44const PB_MAPPER_HALF_CLOSE_IDLE_TIMEOUT: &str = "PB_MAPPER_HALF_CLOSE_IDLE_TIMEOUT";
45
46tokio::task_local! {
47 static TUNNEL_IDLE_OVERRIDE: Duration;
48}
49
50pub async fn with_tunnel_idle_timeout<F: Future>(timeout: Duration, forward: F) -> F::Output {
56 TUNNEL_IDLE_OVERRIDE.scope(timeout, forward).await
57}
58
59#[derive(Debug, Clone, Copy)]
60struct ForwardTimeoutConfig {
61 tunnel_idle_timeout: Duration,
62 half_close_idle_timeout: Duration,
63}
64
65impl ForwardTimeoutConfig {
66 fn from_env() -> Self {
67 Self {
68 tunnel_idle_timeout: TUNNEL_IDLE_OVERRIDE
69 .try_with(|timeout| *timeout)
70 .unwrap_or_else(|_| {
71 duration_from_env(PB_MAPPER_TUNNEL_IDLE_TIMEOUT, DEFAULT_TUNNEL_IDLE_TIMEOUT)
72 }),
73 half_close_idle_timeout: duration_from_env(
74 PB_MAPPER_HALF_CLOSE_IDLE_TIMEOUT,
75 DEFAULT_HALF_CLOSE_IDLE_TIMEOUT,
76 ),
77 }
78 }
79}
80
81pub struct NormalForwardReader<'a, T> {
82 buffered_reader: BufferReader<'a, T>,
83}
84
85impl<'a, T: AsyncReadExt + Unpin + Send> NormalForwardReader<'a, T> {
86 pub fn new(reader: &'a mut T) -> Self {
87 Self {
88 buffered_reader: BufferReader::new(reader),
89 }
90 }
91}
92
93impl<'a, T: AsyncReadExt + Unpin + Send> ForwardReader for NormalForwardReader<'a, T> {
94 async fn read(&mut self) -> Result<&'_ [u8]> {
95 self.buffered_reader.read().await
96 }
97}
98
99pub struct NormalDatagramReader<'a, T: AsyncReadExt + Unpin> {
100 reader: NormalMessageReader<'a, T>,
101}
102
103impl<'a, T: AsyncReadExt + Unpin + Send> NormalDatagramReader<'a, T> {
104 pub fn new(reader: &'a mut T) -> Self {
105 Self {
106 reader: NormalMessageReader::new(reader),
107 }
108 }
109
110 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
111 Self {
112 reader: self.reader.with_checksum_key(key),
113 }
114 }
115}
116
117impl<'a, T: AsyncReadExt + Unpin + Send> DatagramReader for NormalDatagramReader<'a, T> {
118 async fn recv(&mut self) -> Result<Bytes> {
119 let msg = self.reader.read_msg().await?;
120 Ok(Bytes::copy_from_slice(msg))
121 }
122}
123
124pub struct NormalForwardWriter<'a, T> {
125 writer: &'a mut T,
126}
127
128impl<'a, T: AsyncWriteExt + Unpin + Send> NormalForwardWriter<'a, T> {
129 pub fn new(writer: &'a mut T) -> Self {
130 Self { writer }
131 }
132
133 async fn write_inner(&mut self, src: &[u8]) -> Result<()> {
134 self.writer
135 .write_all(src)
136 .await
137 .context(FwdNetworkWriteWithNormalSnafu)
138 }
139}
140
141impl<'a, T: AsyncWriteExt + Unpin + Send> ForwardWriter for NormalForwardWriter<'a, T> {
142 async fn write(&mut self, src: &[u8]) -> Result<()> {
143 self.write_inner(src).await
144 }
145
146 async fn shutdown(&mut self) {
147 let _ = self.writer.shutdown().await;
148 }
149}
150
151pub struct NormalDatagramWriter<'a, T: AsyncWriteExt + Unpin> {
152 writer: NormalMessageWriter<'a, T>,
153}
154
155impl<'a, T: AsyncWriteExt + Unpin + Send> NormalDatagramWriter<'a, T> {
156 pub fn new(writer: &'a mut T) -> Self {
157 Self {
158 writer: NormalMessageWriter::new(writer),
159 }
160 }
161
162 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
163 Self {
164 writer: self.writer.with_checksum_key(key),
165 }
166 }
167}
168
169impl<'a, T: AsyncWriteExt + Unpin + Send> DatagramWriter for NormalDatagramWriter<'a, T> {
170 async fn send(&mut self, src: &[u8]) -> Result<()> {
171 self.writer.write_msg(src).await
172 }
173}
174
175pub struct CodecForwardReader<'a, T: AsyncReadExt + Unpin + Send, D: Decryptor>(
176 CodecMessageReader<'a, T, D>,
177);
178
179impl<'a, T: AsyncReadExt + Send + Unpin, D: Decryptor> CodecForwardReader<'a, T, D> {
180 pub fn new(reader: &'a mut T, decryptor: D) -> Self {
181 Self(CodecMessageReader::new(reader, decryptor))
182 }
183
184 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
185 Self(self.0.with_checksum_key(key))
186 }
187}
188
189impl<'a, T: AsyncReadExt + Send + Unpin, D: Decryptor> ForwardReader
190 for CodecForwardReader<'a, T, D>
191{
192 async fn read(&mut self) -> Result<&'_ [u8]> {
193 self.0.read_stream().await
194 }
195}
196
197pub struct CodecDatagramReader<'a, T: AsyncReadExt + Unpin + Send, D: Decryptor>(
198 CodecMessageReader<'a, T, D>,
199);
200
201impl<'a, T: AsyncReadExt + Send + Unpin, D: Decryptor> CodecDatagramReader<'a, T, D> {
202 pub fn new(reader: &'a mut T, decryptor: D) -> Self {
203 Self(CodecMessageReader::new(reader, decryptor))
204 }
205
206 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
207 Self(self.0.with_checksum_key(key))
208 }
209}
210
211impl<'a, T: AsyncReadExt + Send + Unpin, D: Decryptor> DatagramReader
212 for CodecDatagramReader<'a, T, D>
213{
214 async fn recv(&mut self) -> Result<Bytes> {
215 let msg = self.0.read_msg().await?;
216 Ok(Bytes::copy_from_slice(msg))
217 }
218}
219
220pub struct CodecForwardWriter<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor>(
221 CodecMessageWriter<'a, T, E>,
222);
223
224impl<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor> CodecForwardWriter<'a, T, E> {
225 pub fn new(writer: &'a mut T, encryptor: E) -> Self {
226 Self(CodecMessageWriter::new(writer, encryptor))
227 }
228
229 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
230 Self(self.0.with_checksum_key(key))
231 }
232}
233
234impl<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor> ForwardWriter
235 for CodecForwardWriter<'a, T, E>
236{
237 async fn write(&mut self, src: &[u8]) -> Result<()> {
239 self.0.write_msg(src).await
240 }
241
242 async fn shutdown(&mut self) {
243 let _ = self.0.shutdown().await;
244 }
245}
246
247pub struct CodecDatagramWriter<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor>(
248 CodecMessageWriter<'a, T, E>,
249);
250
251impl<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor> CodecDatagramWriter<'a, T, E> {
252 pub fn new(writer: &'a mut T, encryptor: E) -> Self {
253 Self(CodecMessageWriter::new(writer, encryptor))
254 }
255
256 pub fn with_checksum_key(self, key: AesKeyType) -> Self {
257 Self(self.0.with_checksum_key(key))
258 }
259}
260
261impl<'a, T: AsyncWriteExt + Send + Unpin, E: Encryptor> DatagramWriter
262 for CodecDatagramWriter<'a, T, E>
263{
264 async fn send(&mut self, src: &[u8]) -> Result<()> {
265 let buf = src.to_vec();
266 self.0.write_msg(&buf).await
267 }
268}
269
270pub async fn copy<R: ForwardReader, W: ForwardWriter>(
271 mut reader: R,
272 mut writer: W,
273) -> Result<usize> {
274 let mut length: usize = 0;
275 loop {
276 let src = reader.read().await?;
277 let n = src.len();
278 if n == 0 {
279 break;
280 }
281 writer.write(src).await?;
282 length += n;
283 }
284 writer.shutdown().await;
285 Ok(length)
286}
287
288pub async fn transfer_datagrams<R: DatagramReader, W: DatagramWriter>(
289 label: &'static str,
290 mut reader: R,
291 mut writer: W,
292) -> Result<usize> {
293 let mut _length: usize = 0;
294 loop {
295 let src = reader.recv().await?;
296 let n = src.len();
297 tracing::debug!("datagram forward {label} {n} bytes");
298 writer.send(&src).await?;
299 _length += n;
300 }
301}
302
303pub async fn start_forward<
304 ClientReader: ForwardReader,
305 ClientWriter: ForwardWriter,
306 ServerReader: ForwardReader,
307 ServerWriter: ForwardWriter,
308>(
309 client_reader: ClientReader,
310 client_writer: ClientWriter,
311 server_reader: ServerReader,
312 server_writer: ServerWriter,
313) {
314 start_forward_with_config(
315 client_reader,
316 client_writer,
317 server_reader,
318 server_writer,
319 ForwardTimeoutConfig::from_env(),
320 )
321 .await
322}
323
324struct ForwardActivity {
327 state: parking_lot::Mutex<(usize, Instant)>,
328}
329impl ForwardActivity {
330 fn new() -> Self {
331 Self {
332 state: parking_lot::Mutex::new((0, Instant::now())),
333 }
334 }
335 fn record(&self, n: usize) {
336 let mut state = self.state.lock();
337 state.0 += n;
338 state.1 = Instant::now();
339 }
340 fn snapshot(&self) -> (usize, Instant) {
341 *self.state.lock()
342 }
343}
344
345async fn copy_with_activity<R: ForwardReader, W: ForwardWriter>(
346 mut reader: R,
347 mut writer: W,
348 activity: &ForwardActivity,
349) -> Result<usize> {
350 let mut length = 0;
351 loop {
352 let src = reader.read().await?;
353 if src.is_empty() {
354 break;
355 }
356 writer.write(src).await?;
357 length += src.len();
358 activity.record(src.len());
359 }
360 writer.shutdown().await;
361 Ok(length)
362}
363
364async fn start_forward_with_config<
365 CR: ForwardReader,
366 CW: ForwardWriter,
367 SR: ForwardReader,
368 SW: ForwardWriter,
369>(
370 client_reader: CR,
371 client_writer: CW,
372 server_reader: SR,
373 server_writer: SW,
374 config: ForwardTimeoutConfig,
375) {
376 let client_activity = ForwardActivity::new();
377 let server_activity = ForwardActivity::new();
378 let client_to_server = copy_with_activity(client_reader, server_writer, &client_activity);
379 let server_to_client = copy_with_activity(server_reader, client_writer, &server_activity);
380 tokio::pin!(client_to_server, server_to_client);
381 let idle = tokio::time::sleep(config.tunnel_idle_timeout);
382 let half_close = tokio::time::sleep(config.half_close_idle_timeout);
383 tokio::pin!(idle, half_close);
384 let mut client_result = None;
385 let mut server_result = None;
386 let mut half_closed_at = None;
387 loop {
388 let client_done = client_result.is_some();
389 let server_done = server_result.is_some();
390 if client_done && server_done {
391 break;
392 }
393 tokio::select! {
394 biased;
395 result = &mut client_to_server, if !client_done => {
396 let failed = result.is_err();
397 client_result = Some(result);
398 half_closed_at = Some(Instant::now());
399 reset_sleep(&mut half_close, config.half_close_idle_timeout);
400 if failed { break; }
401 }
402 result = &mut server_to_client, if !server_done => {
403 let failed = result.is_err();
404 server_result = Some(result);
405 half_closed_at = Some(Instant::now());
406 reset_sleep(&mut half_close, config.half_close_idle_timeout);
407 if failed { break; }
408 }
409 _ = &mut idle, if !config.tunnel_idle_timeout.is_zero() && half_closed_at.is_none() => {
410 let last = client_activity.snapshot().1.max(server_activity.snapshot().1);
411 if last.elapsed() >= config.tunnel_idle_timeout { break; }
412 reset_sleep_at(&mut idle, config.tunnel_idle_timeout, last);
413 }
414 _ = &mut half_close, if !config.half_close_idle_timeout.is_zero() && half_closed_at.is_some() => {
415 let last = client_activity.snapshot().1.max(server_activity.snapshot().1).max(half_closed_at.unwrap_or_else(Instant::now));
416 if last.elapsed() >= config.half_close_idle_timeout { break; }
417 reset_sleep_at(&mut half_close, config.half_close_idle_timeout, last);
418 }
419 }
420 }
421 handle_forward_final_result(
422 client_result,
423 client_activity.snapshot().0,
424 "client->server",
425 );
426 handle_forward_final_result(
427 server_result,
428 server_activity.snapshot().0,
429 "server->client",
430 );
431}
432
433fn reset_sleep(sleep: &mut Pin<&mut tokio::time::Sleep>, timeout: Duration) {
434 if !timeout.is_zero() {
435 sleep.as_mut().reset(Instant::now() + timeout);
436 }
437}
438
439fn reset_sleep_at(
440 sleep: &mut Pin<&mut tokio::time::Sleep>,
441 timeout: Duration,
442 activity_at: Instant,
443) {
444 if !timeout.is_zero() {
445 sleep.as_mut().reset(activity_at + timeout);
446 }
447}
448
449fn handle_forward_final_result(result: Option<Result<usize>>, len: usize, detail: &'static str) {
450 if let Some(result) = result {
451 handle_forward_result(result, detail);
452 } else {
453 tracing::debug!("forward stopped before peer closed; we send {len} bytes,detail:{detail}");
454 }
455}
456
457pub async fn start_datagram_forward<
458 ClientReader: DatagramReader,
459 ClientWriter: DatagramWriter,
460 ServerReader: DatagramReader,
461 ServerWriter: DatagramWriter,
462>(
463 client_reader: ClientReader,
464 client_writer: ClientWriter,
465 server_reader: ServerReader,
466 server_writer: ServerWriter,
467) {
468 let client_to_server = transfer_datagrams("udp->tcp", client_reader, server_writer);
469 let server_to_client = transfer_datagrams("tcp->udp", server_reader, client_writer);
470 tokio::select! {
471 result = client_to_server =>{
472 handle_forward_result( result,"udp->tcp");
473 },
474 result = server_to_client =>{
475 handle_forward_result( result,"tcp->udp");
476 }
477 }
478}
479
480fn handle_forward_result(result: Result<usize>, detail: &'static str) {
481 match result {
482 Ok(len) => tracing::info!("forward finish! we send {len} bytes,detail:{detail}"),
483 Err(e) => {
484 if e.is_expected_disconnect() {
486 tracing::debug!("forward closed by peer:{e},detail:{detail}");
487 } else {
488 tracing::error!("got forward error:{e},detail:{detail}");
489 }
490 }
491 }
492}
493
494impl DatagramReader for UdpStreamReadHalf {
495 async fn recv(&mut self) -> Result<Bytes> {
496 self.recv_datagram()
497 .await
498 .map_err(|e| pb_mapper_core::error::Error::MsgForward {
499 action: "read",
500 source: e,
501 })
502 }
503}
504
505impl DatagramWriter for UdpStreamWriteHalf<'_> {
506 async fn send(&mut self, src: &[u8]) -> Result<()> {
507 self.send_datagram(src)
508 .await
509 .map_err(|e| pb_mapper_core::error::Error::MsgForward {
510 action: "write",
511 source: e,
512 })
513 }
514}
515
516pub trait StreamForward: StreamSplit + Sized {
517 fn forward_local_to_remote<'a, R, W>(
518 codec_key: Option<AesKeyType>,
519 framing_key: AesKeyType,
520 local_reader: Self::ReaderRef<'a>,
521 local_writer: Self::WriterRef<'a>,
522 remote_reader: R,
523 remote_writer: W,
524 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
525 where
526 R: AsyncReadExt + Unpin + Send + 'a,
527 W: AsyncWriteExt + Unpin + Send + 'a;
528
529 fn supports_data_v2() -> bool {
532 false
533 }
534
535 fn forward_local_to_remote_with_codec<'a, R, W>(
537 codec: Option<DataCodec>,
538 framing_key: AesKeyType,
539 local_reader: Self::ReaderRef<'a>,
540 local_writer: Self::WriterRef<'a>,
541 remote_reader: R,
542 remote_writer: W,
543 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
544 where
545 R: AsyncReadExt + Unpin + Send + 'a,
546 W: AsyncWriteExt + Unpin + Send + 'a,
547 {
548 if codec.is_some_and(|codec| codec.protocol().is_some()) {
549 return Box::pin(async {
550 Err(crate::secure::protocol_error(
551 "transport does not implement data-v2",
552 ))
553 });
554 }
555 Self::forward_local_to_remote(
556 codec.map(DataCodec::key),
557 framing_key,
558 local_reader,
559 local_writer,
560 remote_reader,
561 remote_writer,
562 )
563 }
564}
565
566impl StreamForward for TcpStreamImpl {
567 fn supports_data_v2() -> bool {
568 true
569 }
570
571 fn forward_local_to_remote<'a, R, W>(
572 codec_key: Option<AesKeyType>,
573 framing_key: AesKeyType,
574 local_reader: Self::ReaderRef<'a>,
575 local_writer: Self::WriterRef<'a>,
576 remote_reader: R,
577 remote_writer: W,
578 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
579 where
580 R: AsyncReadExt + Unpin + Send + 'a,
581 W: AsyncWriteExt + Unpin + Send + 'a,
582 {
583 Self::forward_local_to_remote_with_codec(
584 codec_key.map(DataCodec::legacy),
585 framing_key,
586 local_reader,
587 local_writer,
588 remote_reader,
589 remote_writer,
590 )
591 }
592
593 fn forward_local_to_remote_with_codec<'a, R, W>(
594 codec_key: Option<DataCodec>,
595 framing_key: AesKeyType,
596 local_reader: Self::ReaderRef<'a>,
597 local_writer: Self::WriterRef<'a>,
598 remote_reader: R,
599 remote_writer: W,
600 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
601 where
602 R: AsyncReadExt + Unpin + Send + 'a,
603 W: AsyncWriteExt + Unpin + Send + 'a,
604 {
605 Box::pin(async move {
606 if let Err(error) = local_reader.as_ref().set_nodelay(true) {
610 tracing::warn!(%error, "failed to disable Nagle on local TCP stream");
611 }
612 let mut local_reader = local_reader;
613 let mut local_writer = local_writer;
614 let mut remote_reader = remote_reader;
615 let mut remote_writer = remote_writer;
616 match codec_key {
617 Some(key) => {
618 let (decoder, encoder) = key.endpoint_codecs()?;
619 start_forward(
620 NormalForwardReader::new(&mut local_reader),
621 NormalForwardWriter::new(&mut local_writer),
622 CodecForwardReader::new(&mut remote_reader, decoder)
623 .with_checksum_key(framing_key),
624 CodecForwardWriter::new(&mut remote_writer, encoder)
625 .with_checksum_key(framing_key),
626 )
627 .await;
628 }
629 None => {
630 start_forward(
631 NormalForwardReader::new(&mut local_reader),
632 NormalForwardWriter::new(&mut local_writer),
633 NormalForwardReader::new(&mut remote_reader),
634 NormalForwardWriter::new(&mut remote_writer),
635 )
636 .await;
637 }
638 }
639 Ok(())
640 })
641 }
642}
643
644impl StreamForward for UdpStreamImpl {
645 fn supports_data_v2() -> bool {
646 true
647 }
648
649 fn forward_local_to_remote<'a, R, W>(
650 codec_key: Option<AesKeyType>,
651 framing_key: AesKeyType,
652 local_reader: Self::ReaderRef<'a>,
653 local_writer: Self::WriterRef<'a>,
654 remote_reader: R,
655 remote_writer: W,
656 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
657 where
658 R: AsyncReadExt + Unpin + Send + 'a,
659 W: AsyncWriteExt + Unpin + Send + 'a,
660 {
661 Self::forward_local_to_remote_with_codec(
662 codec_key.map(DataCodec::legacy),
663 framing_key,
664 local_reader,
665 local_writer,
666 remote_reader,
667 remote_writer,
668 )
669 }
670
671 fn forward_local_to_remote_with_codec<'a, R, W>(
672 codec_key: Option<DataCodec>,
673 framing_key: AesKeyType,
674 local_reader: Self::ReaderRef<'a>,
675 local_writer: Self::WriterRef<'a>,
676 remote_reader: R,
677 remote_writer: W,
678 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
679 where
680 R: AsyncReadExt + Unpin + Send + 'a,
681 W: AsyncWriteExt + Unpin + Send + 'a,
682 {
683 Box::pin(async move {
684 let mut remote_reader = remote_reader;
685 let mut remote_writer = remote_writer;
686 match codec_key {
687 Some(key) => {
688 let (decoder, encoder) = key.endpoint_codecs()?;
689 start_datagram_forward(
690 local_reader,
691 local_writer,
692 CodecDatagramReader::new(&mut remote_reader, decoder)
693 .with_checksum_key(framing_key),
694 CodecDatagramWriter::new(&mut remote_writer, encoder)
695 .with_checksum_key(framing_key),
696 )
697 .await;
698 }
699 None => {
700 start_datagram_forward(
701 local_reader,
702 local_writer,
703 NormalDatagramReader::new(&mut remote_reader)
704 .with_checksum_key(framing_key),
705 NormalDatagramWriter::new(&mut remote_writer)
706 .with_checksum_key(framing_key),
707 )
708 .await;
709 }
710 }
711 Ok(())
712 })
713 }
714}
715
716#[cfg(test)]
717mod tests {
718 #[tokio::test]
719 async fn encrypted_stream_fin_requires_complete_authenticated_frames() {
720 use crate::{data::DATA_PROTOCOL_V2, secure::HeaderProtocol};
721 for protocol in [None, Some(DATA_PROTOCOL_V2)] {
722 let codec = DataCodec::negotiate([7; 32], protocol, HeaderProtocol::V2).unwrap();
723 let (_, encoder) = codec.endpoint_codecs().unwrap();
724 let mut wire = Vec::new();
725 CodecMessageWriter::for_session_key(&mut wire, encoder, [8; 32])
726 .write_msg(b"response tail")
727 .await
728 .unwrap();
729 let (decoder, _) = codec.relay_codecs().unwrap();
730 let mut input = wire.as_slice();
731 let mut reader =
732 CodecForwardReader::new(&mut input, decoder).with_checksum_key([8; 32]);
733 assert_eq!(reader.read().await.unwrap(), b"response tail");
734 assert!(reader.read().await.unwrap().is_empty());
735
736 for end in [3, wire.len() - 1] {
738 let (decoder, _) = codec.relay_codecs().unwrap();
739 let mut input = &wire[..end];
740 assert!(
741 CodecForwardReader::new(&mut input, decoder)
742 .with_checksum_key([8; 32])
743 .read()
744 .await
745 .is_err()
746 );
747 }
748 *wire.last_mut().unwrap() ^= 1;
749 let (decoder, _) = codec.relay_codecs().unwrap();
750 let mut input = wire.as_slice();
751 assert!(
752 CodecForwardReader::new(&mut input, decoder)
753 .with_checksum_key([8; 32])
754 .read()
755 .await
756 .is_err()
757 );
758
759 let (_, encoder) = codec.endpoint_codecs().unwrap();
762 let mut empty = Vec::new();
763 CodecMessageWriter::for_session_key(&mut empty, encoder, [8; 32])
764 .write_msg(&[])
765 .await
766 .unwrap();
767 let (decoder, _) = codec.relay_codecs().unwrap();
768 let mut input = empty.as_slice();
769 let mut reader = CodecMessageReader::for_session_key(&mut input, decoder, [8; 32]);
770 assert!(reader.read_msg().await.unwrap().is_empty());
771 assert!(reader.read_msg().await.is_err());
772 }
773 }
774
775 #[tokio::test]
776 async fn tcp_forward_disables_nagle_on_the_local_leg() {
777 use tokio::net::{TcpListener, TcpStream};
778 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
779 let (local, accepted) = tokio::join!(
780 TcpStream::connect(listener.local_addr().unwrap()),
781 listener.accept()
782 );
783 let socket = local.unwrap().into_std().unwrap();
784 let observer = socket.try_clone().unwrap();
785 assert!(!observer.nodelay().unwrap());
786 let mut local = TcpStreamImpl::new(TcpStream::from_std(socket).unwrap());
787 let (mut peer, _) = accepted.unwrap();
788 let (remote, mut echo) = tokio::io::duplex(64);
789 let forwarding = tokio::spawn(async move {
790 let (reader, writer) = local.split();
791 let (remote_reader, remote_writer) = tokio::io::split(remote);
792 TcpStreamImpl::forward_local_to_remote(
793 None,
794 [0; 32],
795 reader,
796 writer,
797 remote_reader,
798 remote_writer,
799 )
800 .await
801 .unwrap();
802 });
803 peer.write_all(b"x").await.unwrap();
804 assert_eq!(
805 tokio::time::timeout(Duration::from_secs(1), echo.read_u8())
806 .await
807 .unwrap()
808 .unwrap(),
809 b'x'
810 );
811 assert!(observer.nodelay().unwrap());
812 forwarding.abort();
813 }
814
815 use std::collections::VecDeque;
816 use std::io;
817 use std::sync::Arc;
818
819 use parking_lot::Mutex;
820 use std::time::Duration;
821
822 use super::*;
823 use pb_mapper_core::config::parse_duration;
824 use pb_mapper_core::error::Error;
825 use tokio::sync::Notify;
826
827 enum ReadAction {
828 Data(Vec<u8>),
829 Eof,
830 Pending,
831 Error(io::ErrorKind),
832 }
833
834 struct ScriptedReader {
835 actions: VecDeque<ReadAction>,
836 current: Vec<u8>,
837 }
838
839 impl ScriptedReader {
840 fn new(actions: impl IntoIterator<Item = ReadAction>) -> Self {
841 Self {
842 actions: actions.into_iter().collect(),
843 current: Vec::new(),
844 }
845 }
846 }
847
848 impl ForwardReader for ScriptedReader {
849 async fn read(&mut self) -> Result<&'_ [u8]> {
850 match self.actions.pop_front().unwrap_or(ReadAction::Pending) {
851 ReadAction::Data(data) => {
852 self.current = data;
853 Ok(&self.current)
854 }
855 ReadAction::Eof => {
856 self.current.clear();
857 Ok(&self.current)
858 }
859 ReadAction::Pending => std::future::pending().await,
860 ReadAction::Error(kind) => Err(Error::MsgForward {
861 action: "read",
862 source: io::Error::new(kind, "scripted read error"),
863 }),
864 }
865 }
866 }
867
868 #[derive(Default)]
869 struct WriterState {
870 chunks: Vec<Vec<u8>>,
871 shutdowns: usize,
872 }
873
874 #[derive(Clone, Default)]
875 struct ScriptedWriter {
876 state: Arc<Mutex<WriterState>>,
877 }
878
879 impl ScriptedWriter {
880 fn chunks(&self) -> Vec<Vec<u8>> {
881 self.state.lock().chunks.clone()
882 }
883
884 fn shutdowns(&self) -> usize {
885 self.state.lock().shutdowns
886 }
887 }
888
889 impl ForwardWriter for ScriptedWriter {
890 async fn write(&mut self, src: &[u8]) -> Result<()> {
891 self.state.lock().chunks.push(src.to_vec());
892 Ok(())
893 }
894
895 async fn shutdown(&mut self) {
896 self.state.lock().shutdowns += 1;
897 }
898 }
899
900 struct EofAfterWriteStartsReader {
901 write_started: Arc<Notify>,
902 returned_eof: bool,
903 empty: Vec<u8>,
904 }
905
906 impl EofAfterWriteStartsReader {
907 fn new(write_started: Arc<Notify>) -> Self {
908 Self {
909 write_started,
910 returned_eof: false,
911 empty: Vec::new(),
912 }
913 }
914 }
915
916 impl ForwardReader for EofAfterWriteStartsReader {
917 async fn read(&mut self) -> Result<&'_ [u8]> {
918 if self.returned_eof {
919 return std::future::pending().await;
920 }
921 self.write_started.notified().await;
922 self.returned_eof = true;
923 Ok(&self.empty)
924 }
925 }
926
927 #[derive(Clone)]
928 struct DelayedWriter {
929 state: Arc<Mutex<WriterState>>,
930 write_started: Arc<Notify>,
931 delay: Duration,
932 }
933
934 impl DelayedWriter {
935 fn new(write_started: Arc<Notify>, delay: Duration) -> Self {
936 Self {
937 state: Arc::new(Mutex::new(WriterState::default())),
938 write_started,
939 delay,
940 }
941 }
942
943 fn chunks(&self) -> Vec<Vec<u8>> {
944 self.state.lock().chunks.clone()
945 }
946 }
947
948 impl ForwardWriter for DelayedWriter {
949 async fn write(&mut self, src: &[u8]) -> Result<()> {
950 self.write_started.notify_one();
951 tokio::time::sleep(self.delay).await;
952 self.state.lock().chunks.push(src.to_vec());
953 Ok(())
954 }
955
956 async fn shutdown(&mut self) {
957 self.state.lock().shutdowns += 1;
958 }
959 }
960
961 #[test]
962 fn parse_duration_accepts_suffixes_and_plain_seconds() {
963 assert_eq!(parse_duration("42"), Some(Duration::from_secs(42)));
964 assert_eq!(parse_duration("500ms"), Some(Duration::from_millis(500)));
965 assert_eq!(parse_duration("2s"), Some(Duration::from_secs(2)));
966 assert_eq!(parse_duration("3m"), Some(Duration::from_secs(180)));
967 assert_eq!(parse_duration("1h"), Some(Duration::from_secs(3600)));
968 assert_eq!(parse_duration(""), None);
969 assert_eq!(parse_duration("bad"), None);
970 assert_eq!(parse_duration("18446744073709551615h"), None);
971 }
972
973 #[tokio::test]
974 async fn half_close_idle_timeout_closes_stalled_peer() {
975 let client_reader = ScriptedReader::new([ReadAction::Eof]);
976 let client_writer = ScriptedWriter::default();
977 let server_reader = ScriptedReader::new([ReadAction::Pending]);
978 let server_writer = ScriptedWriter::default();
979 let server_writer_state = server_writer.clone();
980
981 tokio::time::timeout(
982 Duration::from_millis(200),
983 start_forward_with_config(
984 client_reader,
985 client_writer,
986 server_reader,
987 server_writer,
988 ForwardTimeoutConfig {
989 tunnel_idle_timeout: Duration::from_secs(60 * 60),
990 half_close_idle_timeout: Duration::from_millis(20),
991 },
992 ),
993 )
994 .await
995 .expect("half-closed tunnel did not stop after half-close idle timeout");
996
997 assert_eq!(server_writer_state.shutdowns(), 1);
998 }
999
1000 #[tokio::test]
1001 async fn expected_disconnect_stops_waiting_for_pending_peer() {
1002 let client_reader =
1003 ScriptedReader::new([ReadAction::Error(io::ErrorKind::ConnectionReset)]);
1004 let client_writer = ScriptedWriter::default();
1005 let server_reader = ScriptedReader::new([ReadAction::Pending]);
1006 let server_writer = ScriptedWriter::default();
1007
1008 tokio::time::timeout(
1009 Duration::from_millis(200),
1010 start_forward_with_config(
1011 client_reader,
1012 client_writer,
1013 server_reader,
1014 server_writer,
1015 ForwardTimeoutConfig {
1016 tunnel_idle_timeout: Duration::from_secs(60 * 60),
1017 half_close_idle_timeout: Duration::from_secs(60),
1018 },
1019 ),
1020 )
1021 .await
1022 .expect("expected disconnect did not stop the tunnel");
1023 }
1024
1025 #[tokio::test]
1026 async fn half_closed_tunnel_drains_peer_before_timeout() {
1027 let client_reader = ScriptedReader::new([ReadAction::Eof]);
1028 let client_writer = ScriptedWriter::default();
1029 let client_writer_state = client_writer.clone();
1030 let server_reader =
1031 ScriptedReader::new([ReadAction::Data(b"response".to_vec()), ReadAction::Eof]);
1032 let server_writer = ScriptedWriter::default();
1033
1034 tokio::time::timeout(
1035 Duration::from_millis(200),
1036 start_forward_with_config(
1037 client_reader,
1038 client_writer,
1039 server_reader,
1040 server_writer,
1041 ForwardTimeoutConfig {
1042 tunnel_idle_timeout: Duration::from_secs(60 * 60),
1043 half_close_idle_timeout: Duration::from_millis(200),
1044 },
1045 ),
1046 )
1047 .await
1048 .expect("half-closed tunnel failed to drain the peer");
1049
1050 assert_eq!(client_writer_state.chunks(), vec![b"response".to_vec()]);
1051 assert_eq!(client_writer_state.shutdowns(), 1);
1052 }
1053
1054 #[tokio::test]
1055 async fn delayed_tail_write_survives_peer_half_close() {
1056 let write_started = Arc::new(Notify::new());
1057 let client_reader = EofAfterWriteStartsReader::new(write_started.clone());
1058 let client_writer = DelayedWriter::new(write_started, Duration::from_millis(20));
1059 let client_writer_state = client_writer.clone();
1060 let tail = vec![0x5a; 499];
1061 let server_reader = ScriptedReader::new([ReadAction::Data(tail.clone()), ReadAction::Eof]);
1062 let server_writer = ScriptedWriter::default();
1063
1064 tokio::time::timeout(
1065 Duration::from_millis(300),
1066 start_forward_with_config(
1067 client_reader,
1068 client_writer,
1069 server_reader,
1070 server_writer,
1071 ForwardTimeoutConfig {
1072 tunnel_idle_timeout: Duration::from_secs(60 * 60),
1073 half_close_idle_timeout: Duration::from_millis(200),
1074 },
1075 ),
1076 )
1077 .await
1078 .expect("delayed response tail was lost after the peer half-closed");
1079
1080 assert_eq!(client_writer_state.chunks(), vec![tail]);
1081 }
1082
1083 #[tokio::test]
1084 async fn open_tunnel_idle_timeout_closes_inactive_tunnel() {
1085 let client_reader = ScriptedReader::new([ReadAction::Pending]);
1086 let client_writer = ScriptedWriter::default();
1087 let server_reader = ScriptedReader::new([ReadAction::Pending]);
1088 let server_writer = ScriptedWriter::default();
1089
1090 tokio::time::timeout(
1091 Duration::from_millis(200),
1092 start_forward_with_config(
1093 client_reader,
1094 client_writer,
1095 server_reader,
1096 server_writer,
1097 ForwardTimeoutConfig {
1098 tunnel_idle_timeout: Duration::from_millis(20),
1099 half_close_idle_timeout: Duration::from_secs(60),
1100 },
1101 ),
1102 )
1103 .await
1104 .expect("inactive open tunnel did not stop after tunnel idle timeout");
1105 }
1106}