1use std::{collections::HashSet, sync::Arc, time::Duration};
4
5use iroh_base::EndpointId;
6use n0_error::{e, stack_error};
7use n0_future::{SinkExt, StreamExt};
8use rand::RngExt;
9use time::{Date, OffsetDateTime};
10use tokio::{
11 sync::{
12 mpsc::{self, error::TrySendError},
13 watch,
14 },
15 time::MissedTickBehavior,
16};
17use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
18use tracing::{Instrument, debug, trace, warn};
19
20use crate::{
21 PingTracker,
22 defaults::timeouts::SERVER_WRITE_TIMEOUT,
23 http::ProtocolVersion,
24 protos::{
25 relay::{
26 ClientToRelayMsg, Datagrams, PER_CLIENT_SEND_QUEUE_DEPTH, PING_INTERVAL,
27 RelayToClientMsg, Status,
28 },
29 streams::BytesStreamSink,
30 },
31 server::{
32 ConnectionId, OnDisconnectGuard,
33 clients::Clients,
34 metrics::Metrics,
35 streams::{RecvError as RelayRecvError, RelayedStream, SendError as RelaySendError},
36 },
37};
38
39#[derive(Debug, Clone)]
41pub(super) struct Packet {
42 src: EndpointId,
44 data: Datagrams,
46}
47
48#[derive(Debug)]
52#[non_exhaustive]
53pub struct Config<S> {
54 pub guard: OnDisconnectGuard,
58 pub stream: RelayedStream<S>,
60 pub write_timeout: Duration,
62 pub channel_capacity: usize,
64 pub protocol_version: ProtocolVersion,
66 pub(crate) rate_limited: Option<watch::Receiver<u64>>,
72}
73
74impl<S> Config<S> {
75 pub fn new(
79 guard: OnDisconnectGuard,
80 stream: RelayedStream<S>,
81 protocol_version: ProtocolVersion,
82 ) -> Self {
83 Self {
84 guard,
85 stream,
86 protocol_version,
87 write_timeout: SERVER_WRITE_TIMEOUT,
88 channel_capacity: PER_CLIENT_SEND_QUEUE_DEPTH,
89 rate_limited: None,
90 }
91 }
92}
93
94#[derive(Debug)]
99pub(super) struct Client {
100 endpoint_id: EndpointId,
102 connection_id: ConnectionId,
104 done: CancellationToken,
106 handle: AbortOnDropHandle<()>,
108 packet_queue: mpsc::Sender<Packet>,
110 message_queue: mpsc::Sender<RelayToClientMsg>,
112 protocol_version: ProtocolVersion,
114}
115
116impl Client {
117 pub(super) fn new<S>(config: Config<S>, clients: &Clients, metrics: Arc<Metrics>) -> Client
125 where
126 S: BytesStreamSink + Send + 'static,
127 {
128 let Config {
129 guard,
130 stream,
131 write_timeout,
132 channel_capacity,
133 protocol_version,
134 rate_limited,
135 } = config;
136 let endpoint_id = guard.endpoint_id;
137 let connection_id = guard.connection_id;
138
139 let (packet_send_queue_s, packet_send_queue_r) = mpsc::channel(channel_capacity);
140 let (message_send_queue_s, message_send_queue_r) = mpsc::channel(channel_capacity);
141 let done = CancellationToken::new();
142
143 let actor = Actor {
144 stream,
145 timeout: write_timeout,
146 packet_send_queue: packet_send_queue_r,
147 message_send_queue: message_send_queue_r,
148 guard,
149 clients: clients.clone(),
150 client_counter: ClientCounter::default(),
151 ping_tracker: PingTracker::default(),
152 protocol_version,
153 rate_limited,
154 metrics,
155 };
156
157 let io_done = done.clone();
159 let handle = tokio::task::spawn(actor.run(io_done).instrument(tracing::info_span!(
160 "client-connection-actor",
161 remote_endpoint = %endpoint_id.fmt_short(),
162 connection_id = %connection_id
163 )));
164
165 Client {
166 endpoint_id,
167 connection_id,
168 handle: AbortOnDropHandle::new(handle),
169 done,
170 packet_queue: packet_send_queue_s,
171 message_queue: message_send_queue_s,
172 protocol_version,
173 }
174 }
175
176 pub(super) fn connection_id(&self) -> ConnectionId {
177 self.connection_id
178 }
179
180 pub(super) async fn shutdown(self) {
184 self.start_shutdown();
185 if let Err(e) = self.handle.await {
186 warn!(
187 remote_endpoint = %self.endpoint_id.fmt_short(),
188 "error closing actor loop: {e:#?}",
189 );
190 };
191 }
192
193 pub(super) fn start_shutdown(&self) {
195 self.done.cancel();
196 }
197
198 pub(super) fn try_send_packet(
199 &self,
200 src: EndpointId,
201 data: Datagrams,
202 ) -> Result<(), TrySendError<Packet>> {
203 self.packet_queue.try_send(Packet { src, data })
204 }
205
206 pub(super) fn try_send_peer_gone(
207 &self,
208 key: EndpointId,
209 ) -> Result<(), TrySendError<RelayToClientMsg>> {
210 self.message_queue
211 .try_send(RelayToClientMsg::EndpointGone(key))
212 }
213
214 pub(super) fn try_send_health(
215 &self,
216 status: Status,
217 ) -> Result<(), TrySendError<RelayToClientMsg>> {
218 let message = match self.protocol_version {
219 ProtocolVersion::V2 => RelayToClientMsg::Status(status),
220 ProtocolVersion::V1 => RelayToClientMsg::Health {
221 problem: status.to_string(),
222 },
223 };
224 self.message_queue.try_send(message)
225 }
226}
227
228async fn rate_limited_signal(rx: &mut Option<watch::Receiver<u64>>) -> bool {
232 match rx {
233 Some(rx) => match rx.changed().await {
234 Ok(()) => *rx.borrow_and_update() > 0,
235 Err(_) => false,
238 },
239 None => std::future::pending().await,
240 }
241}
242
243#[stack_error(derive, add_meta, from_sources)]
245#[allow(missing_docs)]
246#[non_exhaustive]
247pub enum HandleFrameError {
248 #[error(transparent)]
249 ForwardPacket { source: ForwardPacketError },
250 #[error("Stream terminated")]
251 StreamTerminated {},
252 #[error(transparent)]
253 Recv { source: RelayRecvError },
254 #[error(transparent)]
255 Send { source: WriteFrameError },
256}
257
258#[stack_error(derive, add_meta, from_sources)]
260#[allow(missing_docs)]
261#[non_exhaustive]
262pub enum WriteFrameError {
263 #[error(transparent)]
264 Stream { source: RelaySendError },
265 #[error(transparent)]
266 Timeout {
267 #[error(std_err)]
268 source: tokio::time::error::Elapsed,
269 },
270}
271
272#[stack_error(derive, add_meta)]
274#[allow(missing_docs)]
275#[non_exhaustive]
276pub enum RunError {
277 #[error(transparent)]
278 ForwardPacket {
279 #[error(from)]
280 source: ForwardPacketError,
281 },
282 #[error("Flush")]
283 Flush {},
284 #[error(transparent)]
285 HandleFrame {
286 #[error(from)]
287 source: HandleFrameError,
288 },
289 #[error("Failed to send packet")]
290 PacketSend { source: WriteFrameError },
291 #[error("Handle was dropped")]
292 HandleDropped {},
293 #[error("Writing a frame failed")]
294 WriteFrame { source: WriteFrameError },
295 #[error("Tick flush")]
296 TickFlush {},
297}
298
299#[derive(Debug)]
317struct Actor<S> {
318 stream: RelayedStream<S>,
320 timeout: Duration,
322 packet_send_queue: mpsc::Receiver<Packet>,
324 message_send_queue: mpsc::Receiver<RelayToClientMsg>,
326 guard: OnDisconnectGuard,
330 clients: Clients,
332 client_counter: ClientCounter,
334 ping_tracker: PingTracker,
335 protocol_version: ProtocolVersion,
337 rate_limited: Option<watch::Receiver<u64>>,
339 metrics: Arc<Metrics>,
340}
341
342impl<S> Actor<S>
343where
344 S: BytesStreamSink,
345{
346 async fn run(mut self, done: CancellationToken) {
347 self.metrics.accepts.inc();
351 if self.client_counter.update(self.guard.endpoint_id()) {
352 self.metrics.unique_client_keys.inc();
353 }
354 match self.run_inner(done).await {
355 Err(e) => {
356 warn!("actor errored {e:#}, exiting");
357 }
358 Ok(()) => {
359 debug!("actor finished, exiting");
360 }
361 }
362
363 self.clients.unregister(self.guard, &self.metrics);
364 self.metrics.disconnects.inc();
365 }
366
367 async fn run_inner(&mut self, done: CancellationToken) -> Result<(), RunError> {
368 let next_interval = || {
370 let random_secs = rand::rng().random_range(1..=5);
371 Duration::from_secs(random_secs) + PING_INTERVAL
372 };
373
374 let mut ping_interval = tokio::time::interval(next_interval());
375 ping_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
377 ping_interval.tick().await;
378
379 let mut rate_limit_notified = false;
380
381 loop {
382 tokio::select! {
383 biased;
384
385 _ = done.cancelled() => {
386 trace!("actor loop cancelled, exiting");
387 self.stream.flush().await.map_err(|_| e!(RunError::Flush))?;
389 break;
390 }
391 limited = rate_limited_signal(&mut self.rate_limited), if !rate_limit_notified => {
392 rate_limit_notified = true;
395 if limited && self.protocol_version == ProtocolVersion::V2 {
396 debug!("connection is rate-limited, notifying client");
397 self.write_frame(RelayToClientMsg::Status(Status::RateLimited))
398 .await
399 .map_err(|err| e!(RunError::WriteFrame, err))?;
400 }
401 }
402 maybe_frame = self.stream.next() => {
403 self
404 .handle_frame(maybe_frame)
405 .await?;
406 ping_interval.reset();
408 }
409 packet = self.packet_send_queue.recv() => {
411 let packet = packet.ok_or_else(|| e!(RunError::HandleDropped))?;
412 self.send_packet(packet)
413 .await
414 .map_err(|err| e!(RunError::PacketSend, err))?;
415 }
416 message = self.message_send_queue.recv() => {
418 let message = message.ok_or_else(|| e!(RunError::HandleDropped))?;
419 trace!("send {message:?}");
420 self.write_frame(message)
421 .await
422 .map_err(|err| e!(RunError::WriteFrame, err))?;
423 }
424 _ = self.ping_tracker.timeout() => {
425 trace!("pong timed out");
426 break;
427 }
428 _ = ping_interval.tick() => {
429 trace!("keep alive ping");
430 ping_interval.reset_after(next_interval());
432 let data = self.ping_tracker.new_ping();
433 self.write_frame(RelayToClientMsg::Ping(data))
434 .await
435 .map_err(|err| e!(RunError::WriteFrame, err))?;
436 }
437 }
438
439 self.stream
440 .flush()
441 .await
442 .map_err(|_| e!(RunError::TickFlush))?;
443 }
444 Ok(())
445 }
446
447 async fn write_frame(&mut self, frame: RelayToClientMsg) -> Result<(), WriteFrameError> {
451 tokio::time::timeout(self.timeout, self.stream.send(frame)).await??;
452 Ok(())
453 }
454
455 async fn send_raw(&mut self, packet: Packet) -> Result<(), WriteFrameError> {
460 let remote_endpoint_id = packet.src;
461 let datagrams = packet.data;
462
463 if let Ok(len) = datagrams.contents.len().try_into() {
464 self.metrics.bytes_sent.inc_by(len);
465 }
466 self.write_frame(RelayToClientMsg::Datagrams {
467 remote_endpoint_id,
468 datagrams,
469 })
470 .await
471 }
472
473 async fn send_packet(&mut self, packet: Packet) -> Result<(), WriteFrameError> {
474 trace!("send packet");
475 match self.send_raw(packet).await {
476 Ok(()) => {
477 self.metrics.send_packets_sent.inc();
478 Ok(())
479 }
480 Err(err) => {
481 self.metrics.send_packets_dropped.inc();
482 Err(err)
483 }
484 }
485 }
486
487 async fn handle_frame(
489 &mut self,
490 maybe_frame: Option<Result<ClientToRelayMsg, RelayRecvError>>,
491 ) -> Result<(), HandleFrameError> {
492 trace!(?maybe_frame, "handle incoming frame");
493 let frame = match maybe_frame {
494 Some(frame) => frame?,
495 None => return Err(e!(HandleFrameError::StreamTerminated)),
496 };
497
498 match frame {
499 ClientToRelayMsg::Datagrams {
500 dst_endpoint_id: dst_key,
501 datagrams,
502 } => {
503 let packet_len = datagrams.contents.len();
504 if let Err(err @ ForwardPacketError { .. }) =
505 self.handle_frame_send_packet(dst_key, datagrams)
506 {
507 warn!("failed to handle send packet frame: {err:#}");
508 }
509 self.metrics.bytes_recv.inc_by(packet_len as u64);
510 }
511 ClientToRelayMsg::Ping(data) => {
512 self.metrics.got_ping.inc();
513 self.write_frame(RelayToClientMsg::Pong(data)).await?;
515 self.metrics.sent_pong.inc();
516 }
517 ClientToRelayMsg::Pong(data) => {
518 self.ping_tracker.pong_received(data);
519 }
520 }
521 Ok(())
522 }
523
524 fn handle_frame_send_packet(
525 &self,
526 dst: EndpointId,
527 data: Datagrams,
528 ) -> Result<(), ForwardPacketError> {
529 self.metrics.send_packets_recv.inc();
530 self.clients
531 .send_packet(dst, data, self.guard.endpoint_id(), &self.metrics)?;
532
533 Ok(())
534 }
535}
536
537#[derive(Debug)]
538pub(crate) enum SendError {
539 Full,
540 Closed,
541}
542
543#[stack_error(derive, add_meta)]
549#[error("failed to forward packet: {reason:?}")]
550pub struct ForwardPacketError {
551 reason: SendError,
552}
553
554#[derive(Debug)]
556struct ClientCounter {
557 clients: HashSet<EndpointId>,
558 last_clear_date: Date,
559}
560
561impl Default for ClientCounter {
562 fn default() -> Self {
563 Self {
564 clients: HashSet::new(),
565 last_clear_date: OffsetDateTime::now_utc().date(),
566 }
567 }
568}
569
570impl ClientCounter {
571 fn check_and_clear(&mut self) {
572 let today = OffsetDateTime::now_utc().date();
573 if today != self.last_clear_date {
574 self.clients.clear();
575 self.last_clear_date = today;
576 }
577 }
578
579 fn update(&mut self, client: EndpointId) -> bool {
581 self.check_and_clear();
582 self.clients.insert(client)
583 }
584}
585
586#[cfg(test)]
587mod tests {
588 use iroh_base::SecretKey;
589 use n0_error::{Result, StdResultExt, bail_any};
590 use n0_future::Stream;
591 use n0_tracing_test::traced_test;
592 use rand::SeedableRng;
593 use tracing::info;
594
595 use super::*;
596 use crate::{
597 client::conn::Conn,
598 http::ProtocolVersion,
599 protos::{common::FrameType, relay::Status, streams::WsBytesFramed},
600 server::streams::{MaybeTlsStream, RateLimited, ServerRelayedStream},
601 };
602
603 async fn recv_frame<
604 E: std::error::Error + Sync + Send + 'static,
605 S: Stream<Item = Result<RelayToClientMsg, E>> + Unpin,
606 >(
607 frame_type: FrameType,
608 mut stream: S,
609 ) -> Result<RelayToClientMsg> {
610 match stream.next().await {
611 Some(Ok(frame)) => {
612 if frame_type != frame.typ() {
613 bail_any!(
614 "Unexpected frame, got {:?}, but expected {:?}",
615 frame.typ(),
616 frame_type
617 );
618 }
619 Ok(frame)
620 }
621 Some(Err(err)) => Err(err).anyerr(),
622 None => bail_any!("Unexpected EOF, expected frame {frame_type:?}"),
623 }
624 }
625
626 #[tokio::test]
627 #[traced_test]
628 async fn test_client_actor_basic() -> Result {
629 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
630
631 let (send_queue_s, send_queue_r) = mpsc::channel(10);
632 let (message_s, message_r) = mpsc::channel(10);
633
634 let endpoint_id = SecretKey::from_bytes(&rng.random()).public();
635 let (io, io_rw) = tokio::io::duplex(1024);
636 let mut io_rw = Conn::test(io_rw, Default::default());
637 let stream = RelayedStream::test(io);
638
639 let clients = Clients::default();
640 let metrics = Arc::new(Metrics::default());
641 let actor = Actor {
642 stream,
643 timeout: Duration::from_secs(1),
644 packet_send_queue: send_queue_r,
645 message_send_queue: message_r,
646 guard: OnDisconnectGuard::empty(endpoint_id),
647 clients: clients.clone(),
648 client_counter: ClientCounter::default(),
649 ping_tracker: PingTracker::default(),
650 protocol_version: ProtocolVersion::V2,
651 rate_limited: None,
652 metrics,
653 };
654
655 let done = CancellationToken::new();
656 let io_done = done.clone();
657 let handle = tokio::task::spawn(async move { actor.run(io_done).await });
658
659 println!("-- write");
661 let data = b"hello world!";
662
663 println!(" send packet");
665 let packet = Packet {
666 src: endpoint_id,
667 data: Datagrams::from(&data[..]),
668 };
669 send_queue_s
670 .send(packet.clone())
671 .await
672 .std_context("send")?;
673 let frame = recv_frame(FrameType::RelayToClientDatagram, &mut io_rw)
674 .await
675 .anyerr()?;
676 assert_eq!(
677 frame,
678 RelayToClientMsg::Datagrams {
679 remote_endpoint_id: endpoint_id,
680 datagrams: data.to_vec().into()
681 }
682 );
683
684 println!("send peer gone");
686 message_s
687 .send(RelayToClientMsg::EndpointGone(endpoint_id))
688 .await
689 .std_context("send")?;
690 let frame = recv_frame(FrameType::EndpointGone, &mut io_rw)
691 .await
692 .anyerr()?;
693 assert_eq!(frame, RelayToClientMsg::EndpointGone(endpoint_id));
694
695 println!("--read");
697
698 let data = b"pingpong";
700 io_rw.send(ClientToRelayMsg::Ping(*data)).await?;
701
702 println!(" recv pong");
704 let frame = recv_frame(FrameType::Pong, &mut io_rw).await?;
705 assert_eq!(frame, RelayToClientMsg::Pong(*data));
706
707 let target = SecretKey::from_bytes(&rng.random()).public();
708
709 println!(" send packet");
711 let data = b"hello world!";
712 io_rw
713 .send(ClientToRelayMsg::Datagrams {
714 dst_endpoint_id: target,
715 datagrams: Datagrams::from(data),
716 })
717 .await
718 .std_context("send")?;
719
720 done.cancel();
721 handle.await.std_context("join")?;
722 Ok(())
723 }
724
725 fn test_client_builder(
726 key: EndpointId,
727 protocol_version: ProtocolVersion,
728 ) -> (Config<WsBytesFramed<RateLimited<MaybeTlsStream>>>, Conn) {
729 let (server, client) = tokio::io::duplex(1024);
730 let guard = OnDisconnectGuard::empty(key);
731 let mut config = Config::new(guard, ServerRelayedStream::test(server), protocol_version);
732 config.write_timeout = Duration::from_secs(1);
733 config.channel_capacity = 10;
734 (config, Conn::test(client, protocol_version))
735 }
736
737 #[tokio::test]
738 #[traced_test]
739 async fn test_client_v1_protocol() -> Result {
740 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42u64);
741 let a_key = SecretKey::from_bytes(&rng.random()).public();
742 let b_key = SecretKey::from_bytes(&rng.random()).public();
743
744 let (builder_a, mut a_rw) = test_client_builder(a_key, ProtocolVersion::V1);
745
746 let clients = Clients::default();
747 let metrics = Arc::new(Metrics::default());
748 clients.register(builder_a, metrics.clone());
749
750 let data = b"hello world v1!";
752 clients.send_packet(a_key, Datagrams::from(&data[..]), b_key, &metrics)?;
753 let frame = recv_frame(FrameType::RelayToClientDatagram, &mut a_rw).await?;
754 assert_eq!(
755 frame,
756 RelayToClientMsg::Datagrams {
757 remote_endpoint_id: b_key,
758 datagrams: data.to_vec().into(),
759 }
760 );
761
762 clients.shutdown().await;
763 Ok(())
764 }
765
766 #[tokio::test]
767 #[traced_test]
768 async fn test_client_v2_protocol() -> Result {
769 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42u64);
770 let a_key = SecretKey::from_bytes(&rng.random()).public();
771 let b_key = SecretKey::from_bytes(&rng.random()).public();
772
773 let (builder_a, mut a_rw) = test_client_builder(a_key, ProtocolVersion::V2);
774
775 let clients = Clients::default();
776 let metrics = Arc::new(Metrics::default());
777 clients.register(builder_a, metrics.clone());
778
779 let data = b"hello world v2!";
781 clients.send_packet(a_key, Datagrams::from(&data[..]), b_key, &metrics)?;
782 let frame = recv_frame(FrameType::RelayToClientDatagram, &mut a_rw).await?;
783 assert_eq!(
784 frame,
785 RelayToClientMsg::Datagrams {
786 remote_endpoint_id: b_key,
787 datagrams: data.to_vec().into(),
788 }
789 );
790
791 clients.shutdown().await;
792 Ok(())
793 }
794
795 #[tokio::test]
797 #[traced_test]
798 async fn test_duplicate_endpoint_v1_receives_v1health() -> Result {
799 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42u64);
800 let key = SecretKey::from_bytes(&rng.random()).public();
801
802 let (builder_first, mut first_rw) = test_client_builder(key, ProtocolVersion::V1);
803
804 let clients = Clients::default();
805 let metrics = Arc::new(Metrics::default());
806 clients.register(builder_first, metrics.clone());
807
808 let (builder_second, _second_rw) = test_client_builder(key, ProtocolVersion::V1);
811 clients.register(builder_second, metrics.clone());
812
813 let frame = recv_frame(FrameType::Health, &mut first_rw).await?;
814 assert!(
815 matches!(frame, RelayToClientMsg::Health { .. }),
816 "expected V1Health frame for V1 client, got {frame:?}"
817 );
818
819 clients.shutdown().await;
820 Ok(())
821 }
822
823 #[tokio::test]
825 #[traced_test]
826 async fn test_duplicate_endpoint_v2_receives_health() -> Result {
827 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42u64);
828 let key = SecretKey::from_bytes(&rng.random()).public();
829
830 let (builder_first, mut first_rw) = test_client_builder(key, ProtocolVersion::V2);
831
832 let clients = Clients::default();
833 let metrics = Arc::new(Metrics::default());
834 clients.register(builder_first, metrics.clone());
835
836 let (builder_second, _second_rw) = test_client_builder(key, ProtocolVersion::V2);
839 clients.register(builder_second, metrics.clone());
840
841 let frame = recv_frame(FrameType::Status, &mut first_rw).await?;
842 assert_eq!(
843 frame,
844 RelayToClientMsg::Status(Status::SameEndpointIdConnected)
845 );
846
847 clients.shutdown().await;
848 Ok(())
849 }
850
851 #[tokio::test(start_paused = true)]
852 #[traced_test]
853 async fn test_rate_limit() -> Result {
854 const LIMIT: u32 = 50;
855 const MAX_FRAMES: u32 = 100;
856
857 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
858
859 let (io_read, io_write) = tokio::io::duplex((LIMIT * MAX_FRAMES) as _);
861 let mut frame_writer = Conn::test(io_write, Default::default());
862 let (mut stream, _limited) = RelayedStream::test_limited(io_read, LIMIT / 10, LIMIT)?;
864
865 let data = Datagrams::from(b"hello world!!!!!");
867 let target = SecretKey::from_bytes(&rng.random()).public();
868 let frame = ClientToRelayMsg::Datagrams {
869 dst_endpoint_id: target,
870 datagrams: data.clone(),
871 };
872 let frame_len = frame.to_bytes().len();
873 assert_eq!(frame_len, LIMIT as usize);
874
875 info!("-- send packet");
877 frame_writer.send(frame.clone()).await.std_context("send")?;
878 frame_writer.flush().await.std_context("flush")?;
879 let recv_frame = tokio::time::timeout(Duration::from_millis(500), stream.next())
880 .await
881 .expect("timeout")
882 .expect("option")
883 .expect("ok");
884 assert_eq!(recv_frame, frame);
885
886 info!("-- send packet");
888 frame_writer.send(frame.clone()).await.std_context("send")?;
889 frame_writer.flush().await.std_context("flush")?;
890 let res = tokio::time::timeout(Duration::from_millis(100), stream.next()).await;
891 assert!(res.is_err(), "expecting a timeout");
892 info!("-- timeout happened");
893
894 info!("-- sleep");
896 tokio::time::sleep(Duration::from_secs(1)).await;
897
898 let recv_frame = tokio::time::timeout(Duration::from_millis(500), stream.next())
900 .await
901 .expect("timeout")
902 .expect("option")
903 .expect("ok");
904 assert_eq!(recv_frame, frame);
905
906 Ok(())
907 }
908
909 #[tokio::test(start_paused = true)]
911 #[traced_test]
912 async fn test_rate_limit_notice() -> Result {
913 const LIMIT: u32 = 50;
914
915 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
916 let key = SecretKey::from_bytes(&rng.random()).public();
917 let target = SecretKey::from_bytes(&rng.random()).public();
918
919 let (server_io, client_io) = tokio::io::duplex(4096);
920 let (stream, limited) = ServerRelayedStream::test_limited(server_io, LIMIT / 10, LIMIT)?;
922 let mut config = Config::new(OnDisconnectGuard::empty(key), stream, ProtocolVersion::V2);
923 config.write_timeout = Duration::from_secs(1);
924 config.channel_capacity = 10;
925 config.rate_limited = Some(limited);
926 let mut conn = Conn::test(client_io, ProtocolVersion::V2);
927
928 let clients = Clients::default();
929 clients.register(config, Arc::new(Metrics::default()));
930
931 conn.send(ClientToRelayMsg::Datagrams {
933 dst_endpoint_id: target,
934 datagrams: Datagrams::from(b"hello world!!!!!"),
935 })
936 .await?;
937
938 let frame = recv_frame(FrameType::Status, &mut conn).await?;
939 assert_eq!(frame, RelayToClientMsg::Status(Status::RateLimited));
940
941 clients.shutdown().await;
942 Ok(())
943 }
944}