1use std::{
17 net::{self},
18 sync::Arc,
19 time::{Duration, SystemTime},
20};
21
22use scion_quic::socket::{BoxedSocketError, GenericScionUdpSocket};
23use sciparse::{
24 address::{addr::ScionAddr, ip_socket_addr::ScionSocketIpAddr},
25 core::{model::Model, view::View},
26 dataplane_path::view::ScionDpPathViewExt,
27 packet::{
28 model::{ScionScmpPacket, ScionUdpPacket},
29 view::ScionRawPacketView,
30 },
31 path::ScionPath,
32 payload::{
33 ProtocolNumber,
34 scmp::{model::ScmpMessage, view::ScmpPayloadView},
35 },
36};
37
38use super::{BoundUnderlaySocket, MAX_UNDERLAY_PACKET_SIZE, UnderlaySocket, UnderlaySocketExt};
39use crate::{
40 internal::Subscribers,
41 path::manager::{MultiPathManager, traits::PathManager},
42 stack::{
43 ScionSocketConnectError, ScionSocketReceiveError, ScionSocketSendError,
44 scmp_handler::ScmpHandler,
45 },
46};
47
48pub struct PathUnawareUdpScionSocket {
50 inner: Box<dyn UnderlaySocket>,
51 local_addr: ScionSocketIpAddr,
53 snap_data_plane: Option<net::SocketAddr>,
55 scmp_handlers: Vec<Box<dyn ScmpHandler>>,
57}
58
59#[allow(clippy::missing_fields_in_debug)]
61impl std::fmt::Debug for PathUnawareUdpScionSocket {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 f.debug_struct("PathUnawareUdpScionSocket")
64 .field("local_addr", &self.local_addr)
65 .finish()
66 }
67}
68
69impl PathUnawareUdpScionSocket {
70 pub(crate) fn new(
71 bound: BoundUnderlaySocket,
72 scmp_handlers: Vec<Box<dyn ScmpHandler>>,
73 ) -> Self {
74 Self {
75 inner: bound.socket,
76 local_addr: bound.local_addr,
77 snap_data_plane: bound.snap_data_plane,
78 scmp_handlers,
79 }
80 }
81
82 pub async fn send_to_via(
89 &self,
90 payload: &[u8],
91 destination: ScionSocketIpAddr,
92 path: &ScionPath,
93 ) -> Result<(), ScionSocketSendError> {
94 let packet = ScionUdpPacket::new(
96 self.local_addr.into(),
97 destination.into(),
98 path.dp_path().to_model(),
99 payload.to_vec(),
100 )
101 .try_encode_to_owned_view()
102 .map_err(|e| {
103 ScionSocketSendError::InvalidPacket(format!("error encoding packet: {e}").into())
104 })?
105 .into_raw();
106
107 self.inner.send(&packet).await
108 }
109
110 #[allow(clippy::type_complexity)]
120 pub async fn recv_from_with_path(
121 &self,
122 buffer: &mut [u8],
123 ) -> Result<(usize, ScionSocketIpAddr, ScionPath), ScionSocketReceiveError> {
124 let mut scratch = vec![0u8; MAX_UNDERLAY_PACKET_SIZE];
125 loop {
126 let n = self.inner.recv(&mut scratch).await?;
127 let (packet, _rest) = ScionRawPacketView::try_from_slice(&scratch[..n])
128 .expect("underlay recv returns a decoded packet");
129
130 match packet.header().next_header() {
131 ProtocolNumber::Udp => {}
132 ProtocolNumber::Scmp => {
133 tracing::debug!("SCMP packet received, forwarding to SCMP handlers");
134 for handler in &self.scmp_handlers {
135 let Some(reply) = handler.handle(packet) else {
137 continue;
138 };
139
140 let reply = match reply.try_encode_to_owned_view() {
141 Ok(reply) => reply,
142 Err(e) => {
143 tracing::warn!(error = %e, "failed to encode SCMP reply");
144 continue;
145 }
146 };
147
148 if let Err(e) = self.inner.try_send(&reply) {
149 tracing::warn!(error = %e, "failed to send SCMP reply");
150 }
151 }
152 continue;
153 }
154 next_header => {
155 tracing::debug!(%next_header, "Packet with unexpected next layer protocol, skipping");
156 continue;
157 }
158 }
159
160 let packet = match packet.try_as_udp() {
161 Ok(packet) => packet,
162 Err(e) => {
163 tracing::debug!(error = %e, "Received invalid UDP packet, skipping");
164 continue;
165 }
166 };
167 let src_addr = match packet.src_socket_addr() {
168 Ok(src_addr) => src_addr,
169 Err(err) => {
170 tracing::debug!(
171 %err,
172 "Failed to decode packet source address, skipping"
173 );
174 continue;
175 }
176 };
177
178 tracing::trace!(
179 src = %src_addr,
180 length = packet.udp().payload().len(),
181 "received packet",
182 );
183
184 let Some(src_addr) = src_addr.try_to_scion_sock_ip_addr() else {
185 tracing::debug!("Received packet with non-IP source address, skipping");
186 continue;
187 };
188
189 let max_read = std::cmp::min(buffer.len(), packet.udp().payload().len());
190 buffer[..max_read].copy_from_slice(&packet.udp().payload()[..max_read]);
191
192 let path = ScionPath::new(
196 src_addr.isd_asn(),
197 packet.header().dst_ia(),
198 packet.header().path().to_owned_view(),
199 None,
200 None,
201 );
202
203 return Ok((packet.udp().payload().len(), src_addr, path));
204 }
205 }
206
207 pub async fn recv_from(
215 &self,
216 buffer: &mut [u8],
217 ) -> Result<(usize, ScionSocketIpAddr), ScionSocketReceiveError> {
218 let mut scratch = vec![0u8; MAX_UNDERLAY_PACKET_SIZE];
219 loop {
220 let n = self.inner.recv(&mut scratch).await?;
221 let (packet, _rest) = ScionRawPacketView::try_from_slice(&scratch[..n])
222 .expect("underlay recv returns a decoded packet");
223
224 match packet.header().next_header() {
225 ProtocolNumber::Udp => {}
226 ProtocolNumber::Scmp => {
227 tracing::debug!("SCMP packet received, forwarding to SCMP handlers");
228 for handler in &self.scmp_handlers {
229 let Some(reply) = handler.handle(packet) else {
231 continue;
232 };
233
234 let reply = match reply.try_encode_to_owned_view() {
235 Ok(reply) => reply,
236 Err(e) => {
237 tracing::warn!(error = %e, "failed to encode SCMP reply");
238 continue;
239 }
240 };
241
242 if let Err(e) = self.inner.try_send(&reply) {
243 tracing::warn!(error = %e, "failed to send SCMP reply");
244 }
245 }
246 continue;
247 }
248 next_header => {
249 tracing::debug!(%next_header, "Packet with unknown next layer protocol, skipping");
250 continue;
251 }
252 }
253
254 let packet = match packet.try_as_udp() {
255 Ok(packet) => packet,
256 Err(e) => {
257 tracing::debug!(error = %e, "Received invalid UDP packet, dropping");
258 continue;
259 }
260 };
261
262 let src_addr = match packet.src_socket_addr() {
263 Ok(src_addr) => src_addr,
264 Err(err) => {
265 tracing::debug!(%err, "Failed to decode packet source address, skipping");
266 continue;
267 }
268 };
269
270 tracing::trace!(
271 src = %src_addr,
272 length = packet.udp().payload().len(),
273 buffer_size = buffer.len(),
274 "received packet",
275 );
276
277 let Some(src_addr) = src_addr.try_to_scion_sock_ip_addr() else {
278 tracing::debug!("Received packet with non-IP source address, skipping");
279 continue;
280 };
281
282 let max_read = std::cmp::min(buffer.len(), packet.udp().payload().len());
283 buffer[..max_read].copy_from_slice(&packet.udp().payload()[..max_read]);
284
285 return Ok((packet.udp().payload().len(), src_addr));
286 }
287 }
288
289 pub fn local_addr(&self) -> ScionSocketIpAddr {
291 self.local_addr
292 }
293
294 pub fn snap_data_plane(&self) -> Option<net::SocketAddr> {
296 self.snap_data_plane
297 }
298
299 pub fn into_path_aware<P: PathManager>(
307 self,
308 path_manager: Arc<P>,
309 connect_timeout: Duration,
310 ) -> UdpScionSocket<P> {
311 UdpScionSocket::new(self, path_manager, connect_timeout, Subscribers::default())
312 }
313}
314
315pub struct ScmpScionSocket {
317 inner: Box<dyn UnderlaySocket>,
318 local_addr: ScionSocketIpAddr,
320 snap_data_plane: Option<net::SocketAddr>,
322}
323
324impl ScmpScionSocket {
325 pub(crate) fn new(bound: BoundUnderlaySocket) -> Self {
326 Self {
327 inner: bound.socket,
328 local_addr: bound.local_addr,
329 snap_data_plane: bound.snap_data_plane,
330 }
331 }
332}
333
334impl ScmpScionSocket {
335 pub async fn send_to_via(
337 &self,
338 message: ScmpMessage,
339 destination: ScionAddr,
340 path: &ScionPath,
341 ) -> Result<(), ScionSocketSendError> {
342 let packet = ScionScmpPacket::new(
343 self.local_addr.scion_ip_addr().into(),
344 destination,
345 path.dp_path().to_model(),
346 message,
347 )
348 .try_encode_to_owned_view()
349 .map_err(|e| {
350 ScionSocketSendError::InvalidPacket(format!("error encoding packet: {e}").into())
351 })?
352 .into_raw();
353 self.inner.send(&packet).await
354 }
355
356 #[allow(clippy::type_complexity)]
358 pub async fn recv_from_with_path(
359 &self,
360 ) -> Result<(Box<ScmpPayloadView>, ScionAddr, ScionPath), ScionSocketReceiveError> {
361 let mut scratch = vec![0u8; MAX_UNDERLAY_PACKET_SIZE];
362 loop {
363 let n = self.inner.recv(&mut scratch).await?;
364 let (packet, _rest) = ScionRawPacketView::try_from_slice(&scratch[..n])
365 .expect("underlay recv returns a decoded packet");
366 let packet = match packet.try_as_scmp() {
367 Ok(packet) => packet,
368 Err(e) => {
369 tracing::debug!(error = %e, "Received invalid SCMP packet, dropping");
370 continue;
371 }
372 };
373
374 let src_addr = match packet.src_scion_addr() {
375 Ok(source) => source,
376 Err(e) => {
377 tracing::debug!(error = %e, "Failed to decode packet source address, skipping");
378 continue;
379 }
380 };
381
382 let path = ScionPath::new(
383 packet.header().src_ia(),
384 packet.header().dst_ia(),
385 packet.header().path().to_owned_view(),
386 None,
387 None,
388 );
389
390 return Ok((packet.scmp().to_boxed(), src_addr, path));
391 }
392 }
393
394 pub async fn recv_from(
396 &self,
397 ) -> Result<(Box<ScmpPayloadView>, ScionAddr), ScionSocketReceiveError> {
398 let mut scratch = vec![0u8; MAX_UNDERLAY_PACKET_SIZE];
399 loop {
400 let n = self.inner.recv(&mut scratch).await?;
401 let (packet, _rest) = ScionRawPacketView::try_from_slice(&scratch[..n])
402 .expect("underlay recv returns a decoded packet");
403 let packet = match packet.try_as_scmp() {
404 Ok(packet) => packet,
405 Err(e) => {
406 tracing::debug!(error = %e, "Received invalid SCMP packet, skipping");
407 continue;
408 }
409 };
410 let src_addr = match packet.src_scion_addr() {
411 Ok(source) => source,
412 Err(e) => {
413 tracing::debug!(error = %e, "Failed to decode packet source address, skipping");
414 continue;
415 }
416 };
417 return Ok((packet.scmp().to_boxed(), src_addr));
418 }
419 }
420
421 pub fn local_addr(&self) -> ScionSocketIpAddr {
423 self.local_addr
424 }
425
426 pub fn snap_data_plane(&self) -> Option<net::SocketAddr> {
428 self.snap_data_plane
429 }
430}
431
432pub struct RawScionSocket {
434 inner: Box<dyn UnderlaySocket>,
435 local_addr: ScionSocketIpAddr,
437 snap_data_plane: Option<net::SocketAddr>,
439}
440
441impl RawScionSocket {
442 pub(crate) fn new(bound: BoundUnderlaySocket) -> Self {
443 Self {
444 inner: bound.socket,
445 local_addr: bound.local_addr,
446 snap_data_plane: bound.snap_data_plane,
447 }
448 }
449}
450
451impl RawScionSocket {
452 pub async fn send(&self, packet: &ScionRawPacketView) -> Result<(), ScionSocketSendError> {
454 self.inner.send(packet).await
455 }
456
457 pub async fn recv(&self) -> Result<Box<ScionRawPacketView>, ScionSocketReceiveError> {
459 let mut buf = vec![0u8; MAX_UNDERLAY_PACKET_SIZE];
460 let n = self.inner.recv(&mut buf).await?;
461 let (view, _rest) = ScionRawPacketView::try_from_slice(&buf[..n])
462 .expect("underlay recv returns a decoded packet");
463 Ok(view.to_boxed())
464 }
465
466 pub fn local_addr(&self) -> ScionSocketIpAddr {
468 self.local_addr
469 }
470
471 pub fn snap_data_plane(&self) -> Option<net::SocketAddr> {
473 self.snap_data_plane
474 }
475}
476
477pub trait SendErrorReceiver: Send + Sync {
479 fn report_send_error(&self, error: &ScionSocketSendError);
482}
483
484pub struct UdpScionSocket<P: PathManager = MultiPathManager> {
492 socket: PathUnawareUdpScionSocket,
493 pather: Arc<P>,
494 connect_timeout: Duration,
495 remote_addr: Option<ScionSocketIpAddr>,
496 send_error_receivers: Subscribers<dyn SendErrorReceiver>,
497}
498
499#[allow(clippy::missing_fields_in_debug)]
501impl<P: PathManager> std::fmt::Debug for UdpScionSocket<P> {
502 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
503 f.debug_struct("UdpScionSocket")
504 .field("local_addr", &self.socket.local_addr())
505 .field("remote_addr", &self.remote_addr)
506 .finish()
507 }
508}
509
510impl<P: PathManager> UdpScionSocket<P> {
511 pub(crate) fn new(
513 socket: PathUnawareUdpScionSocket,
514 pather: Arc<P>,
515 connect_timeout: Duration,
516 send_error_receivers: Subscribers<dyn SendErrorReceiver>,
517 ) -> Self {
518 Self {
519 socket,
520 pather,
521 connect_timeout,
522 remote_addr: None,
523 send_error_receivers,
524 }
525 }
526
527 pub async fn connect(
533 self,
534 remote_addr: ScionSocketIpAddr,
535 ) -> Result<Self, ScionSocketConnectError> {
536 let _path = self
538 .pather
539 .path_timeout(
540 self.socket.local_addr().isd_asn(),
541 remote_addr.isd_asn(),
542 SystemTime::now(),
543 self.connect_timeout,
544 )
545 .await?;
546
547 Ok(Self {
548 remote_addr: Some(remote_addr),
549 ..self
550 })
551 }
552
553 pub async fn send(&self, payload: &[u8]) -> Result<(), ScionSocketSendError> {
560 if let Some(remote_addr) = self.remote_addr {
561 self.send_to(payload, remote_addr).await
562 } else {
563 Err(ScionSocketSendError::NotConnected)
564 }
565 }
566
567 pub async fn send_to(
575 &self,
576 payload: &[u8],
577 destination: ScionSocketIpAddr,
578 ) -> Result<(), ScionSocketSendError> {
579 let path = &self
580 .pather
581 .path_wait(
582 self.socket.local_addr().isd_asn(),
583 destination.isd_asn(),
584 SystemTime::now(),
585 )
586 .await?;
587 self.socket.send_to_via(payload, destination, path).await
588 }
589
590 pub async fn send_to_via(
597 &self,
598 payload: &[u8],
599 destination: ScionSocketIpAddr,
600 path: &ScionPath,
601 ) -> Result<(), ScionSocketSendError> {
602 self.socket
603 .send_to_via(payload, destination, path)
604 .await
605 .inspect_err(|e| {
606 self.send_error_receivers
607 .for_each(|receiver| receiver.report_send_error(e));
608 })
609 }
610
611 pub async fn recv_from_with_path(
622 &self,
623 buffer: &mut [u8],
624 ) -> Result<(usize, ScionSocketIpAddr, ScionPath), ScionSocketReceiveError> {
625 let (len, sender_addr, path): (usize, ScionSocketIpAddr, ScionPath) =
626 self.socket.recv_from_with_path(buffer).await?;
627
628 match path.clone().try_into_reversed() {
629 Ok(reversed_path) => {
630 self.pather.register_path(
632 self.socket.local_addr().isd_asn(),
633 sender_addr.isd_asn(),
634 SystemTime::now(),
635 reversed_path,
636 );
637 }
638 Err((_, e)) => {
639 tracing::trace!(error = ?e, "Failed to reverse path for registration");
640 }
641 }
642
643 tracing::trace!(
644 src = %self.socket.local_addr(),
645 dst = %sender_addr,
646 "Registered reverse path",
647 );
648
649 Ok((len, sender_addr, path))
650 }
651
652 pub async fn recv_from(
664 &self,
665 buffer: &mut [u8],
666 ) -> Result<(usize, ScionSocketIpAddr), ScionSocketReceiveError> {
667 let (len, sender_addr, _) = self.recv_from_with_path(buffer).await?;
668 Ok((len, sender_addr))
669 }
670
671 pub async fn recv(&self, buffer: &mut [u8]) -> Result<usize, ScionSocketReceiveError> {
683 if self.remote_addr.is_none() {
684 return Err(ScionSocketReceiveError::NotConnected);
685 }
686 loop {
687 let (len, sender_addr) = self.recv_from(buffer).await?;
688
689 match self.remote_addr {
691 Some(remote_addr) => {
692 if sender_addr == remote_addr {
693 return Ok(len);
694 }
695 }
696 None => return Err(ScionSocketReceiveError::NotConnected),
697 }
698 }
699 }
700
701 pub fn local_addr(&self) -> ScionSocketIpAddr {
703 self.socket.local_addr()
704 }
705
706 pub fn snap_data_plane(&self) -> Option<net::SocketAddr> {
708 self.socket.snap_data_plane()
709 }
710}
711
712#[async_trait::async_trait]
715impl<P: PathManager + Sync + Send + 'static> GenericScionUdpSocket for UdpScionSocket<P> {
716 async fn send_to(
718 &self,
719 payload: &[u8],
720 destination: ScionSocketIpAddr,
721 ) -> Result<(), BoxedSocketError> {
722 self.send_to(payload, destination)
723 .await
724 .map_err(|e| Box::new(e) as BoxedSocketError)
725 }
726
727 async fn recv_from(
730 &self,
731 buf: &mut [u8],
732 ) -> Result<(usize, ScionSocketIpAddr), BoxedSocketError> {
733 self.recv_from(buf)
734 .await
735 .map_err(|e| Box::new(e) as BoxedSocketError)
736 }
737
738 fn local_addr(&self) -> ScionSocketIpAddr {
740 self.local_addr()
741 }
742}
743
744#[cfg(test)]
745mod cancel_safety_tests {
746 use std::{
772 io,
773 net::Ipv4Addr,
774 sync::{Arc, Mutex},
775 time::SystemTime,
776 };
777
778 use async_trait::async_trait;
779 use sciparse::{
780 identifier::{asn::Asn, isd::Isd, isd_asn::IsdAsn},
781 util::test_builder::{TestPathBuilder, TestPathContext},
782 };
783
784 use super::*;
785 use crate::{
786 internal::Subscribers,
787 path::manager::traits::{PathWaitError, SyncPathManager},
788 stack::{ScionSocketReceiveError, ScionSocketSendError, UnderlaySocket},
789 };
790
791 struct ManualUnderlaySocket {
792 rx: tokio::sync::Mutex<tokio::sync::mpsc::Receiver<Box<ScionRawPacketView>>>,
793 peeked: tokio::sync::Mutex<Option<Box<ScionRawPacketView>>>,
796 }
797
798 impl ManualUnderlaySocket {
799 fn new() -> (Self, tokio::sync::mpsc::Sender<Box<ScionRawPacketView>>) {
800 let (inject_tx, recv_rx) = tokio::sync::mpsc::channel::<Box<ScionRawPacketView>>(64);
802 let socket = Self {
803 rx: tokio::sync::Mutex::new(recv_rx),
804 peeked: tokio::sync::Mutex::new(None),
805 };
806 (socket, inject_tx)
807 }
808 }
809
810 #[async_trait]
811 impl UnderlaySocket for ManualUnderlaySocket {
812 fn try_send(&self, _packet: &ScionRawPacketView) -> Result<(), ScionSocketSendError> {
813 Ok(())
814 }
815
816 async fn writeable(&self) {}
817
818 fn try_recv(&self, buf: &mut [u8]) -> Result<usize, ScionSocketReceiveError> {
819 let would_block =
820 || ScionSocketReceiveError::IoError(io::Error::from(io::ErrorKind::WouldBlock));
821
822 let packet: Box<ScionRawPacketView> = {
823 let Ok(mut peeked) = self.peeked.try_lock() else {
824 return Err(would_block());
825 };
826 match peeked.take() {
827 Some(packet) => packet,
828 None => {
829 let Ok(mut rx) = self.rx.try_lock() else {
830 return Err(would_block());
831 };
832 match rx.try_recv() {
833 Ok(packet) => packet,
834 Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {
835 return Err(would_block());
836 }
837 Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => {
838 return Err(ScionSocketReceiveError::IoError(io::Error::other(
839 "channel closed",
840 )));
841 }
842 }
843 }
844 }
845 };
846
847 let bytes = packet.as_slice();
848 let n = bytes.len();
849 buf[..n].copy_from_slice(bytes);
850 Ok(n)
851 }
852
853 async fn readable(&self) {
854 let mut peeked = self.peeked.lock().await;
855 if peeked.is_some() {
856 return;
857 }
858 if let Some(packet) = self.rx.lock().await.recv().await {
861 *peeked = Some(packet);
862 }
863 }
864 }
865
866 #[derive(Default)]
867 struct ImmediatePathManager {
868 registered_paths: Mutex<Vec<ScionPath>>,
869 }
870
871 impl SyncPathManager for ImmediatePathManager {
872 fn register_path(&self, _src: IsdAsn, _dst: IsdAsn, _now: SystemTime, path: ScionPath) {
873 self.registered_paths.lock().expect("poisoned").push(path);
874 }
875
876 fn try_cached_path(
877 &self,
878 src: IsdAsn,
879 _dst: IsdAsn,
880 _now: SystemTime,
881 ) -> io::Result<Option<ScionPath>> {
882 Ok(Some(
883 ScionPath::local(src).expect("src is not a wildcard IA"),
884 ))
885 }
886 }
887
888 impl PathManager for ImmediatePathManager {
889 fn path_wait(
890 &self,
891 src: IsdAsn,
892 _dst: IsdAsn,
893 _now: SystemTime,
894 ) -> impl std::future::Future<Output = Result<ScionPath, PathWaitError>> + Send + '_
895 {
896 async move { Ok(ScionPath::local(src).expect("src is not a wildcard IA")) }
897 }
898 }
899
900 const LOCAL_ISD_ASN: IsdAsn = IsdAsn::new(Isd(1), Asn(1));
901 const REMOTE_ISD_ASN: IsdAsn = IsdAsn::new(Isd(1), Asn(2));
902 const OTHER_ISD_ASN: IsdAsn = IsdAsn::new(Isd(1), Asn(3));
903
904 fn local_addr() -> ScionSocketIpAddr {
905 ScionSocketIpAddr::new(LOCAL_ISD_ASN, Ipv4Addr::LOCALHOST.into(), 8080)
906 }
907
908 fn remote_addr() -> ScionSocketIpAddr {
909 ScionSocketIpAddr::new(REMOTE_ISD_ASN, Ipv4Addr::new(127, 0, 0, 2).into(), 9090)
910 }
911
912 fn other_addr() -> ScionSocketIpAddr {
913 ScionSocketIpAddr::new(OTHER_ISD_ASN, Ipv4Addr::new(127, 0, 0, 3).into(), 7070)
914 }
915
916 fn test_path_ctx(src: ScionAddr, dst: ScionAddr) -> TestPathContext {
918 TestPathBuilder::new(src, dst)
919 .using_info_timestamp(1_000_000)
920 .up()
921 .add_hop(0, 1)
922 .add_hop(1, 0)
923 .build(1_000_000)
924 }
925
926 fn make_udp_raw(
929 src: ScionSocketIpAddr,
930 dst: ScionSocketIpAddr,
931 payload: &[u8],
932 ) -> Box<ScionRawPacketView> {
933 let ctx = test_path_ctx(src.scion_addr(), dst.scion_addr());
934 ctx.scion_packet_udp(payload, src.port(), dst.port())
935 .try_encode_to_owned_view()
936 .expect("should encode")
937 .into()
938 }
939
940 fn build_socket() -> (
943 UdpScionSocket<ImmediatePathManager>,
944 tokio::sync::mpsc::Sender<Box<ScionRawPacketView>>,
945 Arc<ImmediatePathManager>,
946 ) {
947 let (underlay, inject_tx) = ManualUnderlaySocket::new();
948 let pather = Arc::new(ImmediatePathManager::default());
949 let path_unaware = PathUnawareUdpScionSocket::new(
950 BoundUnderlaySocket {
951 socket: Box::new(underlay),
952 local_addr: local_addr(),
953 snap_data_plane: None,
954 },
955 vec![], );
957 let socket = UdpScionSocket::new(
958 path_unaware,
959 pather.clone(),
960 std::time::Duration::from_secs(5),
961 Subscribers::new(),
962 );
963 (socket, inject_tx, pather)
964 }
965
966 #[tokio::test]
974 async fn recv_from_with_path_cancel_while_pending_does_not_lose_packet() {
975 let (socket, inject_tx, _pather) = build_socket();
976
977 {
979 let mut buf = [0u8; 64];
980 let mut fut = std::pin::pin!(socket.recv_from_with_path(&mut buf));
981 let waker = futures::task::noop_waker();
982 let mut cx = std::task::Context::from_waker(&waker);
983 assert!(fut.as_mut().poll(&mut cx).is_pending());
985 }
987
988 let payload = b"cancel-safe";
990 inject_tx
991 .try_send(make_udp_raw(remote_addr(), local_addr(), payload))
992 .unwrap();
993
994 let mut buf2 = vec![0u8; 64];
996 let (len, sender, _path) = socket.recv_from_with_path(&mut buf2).await.unwrap();
997
998 assert_eq!(len, payload.len());
999 assert_eq!(&buf2[..len], payload);
1000 assert_eq!(sender, remote_addr());
1001 }
1002
1003 #[tokio::test]
1006 async fn recv_filters_wrong_sender_and_delivers_correct_packet() {
1007 let (mut socket, inject_tx, _pather) = build_socket();
1008 socket.remote_addr = Some(remote_addr());
1010
1011 inject_tx
1013 .try_send(make_udp_raw(other_addr(), local_addr(), b"wrong"))
1014 .unwrap();
1015 inject_tx
1016 .try_send(make_udp_raw(remote_addr(), local_addr(), b"correct"))
1017 .unwrap();
1018
1019 let mut buf = [0u8; 64];
1020 let len = socket.recv(&mut buf).await.unwrap();
1021 assert_eq!(&buf[..len], b"correct");
1022 }
1023
1024 #[tokio::test]
1027 async fn recv_cancel_during_filtering_socket_remains_usable() {
1028 let (mut socket, inject_tx, _pather) = build_socket();
1029 socket.remote_addr = Some(remote_addr());
1030
1031 inject_tx
1034 .try_send(make_udp_raw(other_addr(), local_addr(), b"wrong"))
1035 .unwrap();
1036
1037 {
1041 let mut filter_buf = [0u8; 64];
1042 let mut fut = std::pin::pin!(socket.recv(&mut filter_buf));
1043 let waker = futures::task::noop_waker();
1044 let mut cx = std::task::Context::from_waker(&waker);
1045 assert!(
1046 fut.as_mut().poll(&mut cx).is_pending(),
1047 "recv must be Pending after consuming wrong-sender packet"
1048 );
1049 }
1051
1052 inject_tx
1054 .try_send(make_udp_raw(remote_addr(), local_addr(), b"after-cancel"))
1055 .unwrap();
1056
1057 let mut buf = [0u8; 64];
1058 let len = socket.recv(&mut buf).await.unwrap();
1059 assert_eq!(&buf[..len], b"after-cancel");
1060 }
1061
1062 #[tokio::test]
1065 async fn recv_from_buffer_valid_only_after_ok() {
1066 let (socket, inject_tx, _pather) = build_socket();
1067
1068 let mut buf = [0xFFu8; 64];
1070
1071 {
1073 let mut fut = std::pin::pin!(socket.recv_from(&mut buf));
1074 let waker = futures::task::noop_waker();
1075 let mut cx = std::task::Context::from_waker(&waker);
1076 assert!(fut.as_mut().poll(&mut cx).is_pending());
1077 }
1078
1079 let payload = b"real-data";
1081 inject_tx
1082 .try_send(make_udp_raw(remote_addr(), local_addr(), payload))
1083 .unwrap();
1084
1085 let (len, _sender) = socket.recv_from(&mut buf).await.unwrap();
1086 assert_eq!(len, payload.len());
1087 assert_eq!(
1088 &buf[..len],
1089 payload,
1090 "buffer must contain the real payload after Ok return"
1091 );
1092 }
1093}