1use std::{
2 marker::PhantomData,
3 net::{SocketAddr, SocketAddrV4, SocketAddrV6},
4 os::fd::AsRawFd,
5 sync::Arc,
6};
7
8use statime_base::{Timestamp, UniversalTimestamp, TAI, UTC};
9use tokio::io::{unix::AsyncFd, Interest};
10
11use crate::{
12 control_message::{ControlMessage, MessageQueue, EXPECTED_MAX_CMSG_SIZE},
13 interface::InterfaceName,
14 networkaddress::{sealed::PrivateToken, MulticastJoinable, NetworkAddress},
15 raw_socket::RawSocket,
16};
17
18#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "macos")))]
19mod fallback;
20#[cfg(target_os = "freebsd")]
21mod freebsd;
22#[cfg(target_os = "linux")]
23mod linux;
24#[cfg(target_os = "macos")]
25mod macos;
26
27#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "macos")))]
28use self::fallback::configure_timestamping;
29#[cfg(target_os = "freebsd")]
30use self::freebsd::configure_timestamping;
31#[cfg(target_os = "linux")]
32pub use self::linux::*;
33#[cfg(target_os = "macos")]
34use self::macos::configure_timestamping;
35
36#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
38pub struct TimestampData {
39 pub timestamp_mode: InterfaceTimestampMode,
43 pub hardware: Option<Timestamp<TAI>>,
45 pub software: Option<Timestamp<UTC>>,
47}
48
49impl TimestampData {
50 fn empty(timestamp_mode: InterfaceTimestampMode) -> Self {
52 Self::default().with_timestamp_mode(timestamp_mode)
53 }
54
55 #[must_use]
60 pub fn selected_timestamp(self) -> Option<UniversalTimestamp> {
61 match self.timestamp_mode {
62 InterfaceTimestampMode::SoftwareAll | InterfaceTimestampMode::SoftwareRecv => {
63 self.software.map(UniversalTimestamp::from)
64 }
65 InterfaceTimestampMode::HardwareAll
66 | InterfaceTimestampMode::HardwareRecv
67 | InterfaceTimestampMode::HardwarePTPAll
68 | InterfaceTimestampMode::HardwarePTPRecv => {
69 self.hardware.map(UniversalTimestamp::from)
70 }
71 InterfaceTimestampMode::None => Option::None,
72 }
73 }
74
75 fn with_timestamp_mode(self, timestamp_mode: InterfaceTimestampMode) -> Self {
77 Self {
78 timestamp_mode,
79 ..self
80 }
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
86pub enum GeneralTimestampMode {
87 SoftwareAll,
89 SoftwareRecv,
91 #[default]
93 None,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
98pub enum InterfaceTimestampMode {
99 HardwareAll,
101 HardwareRecv,
103 HardwarePTPAll,
105 HardwarePTPRecv,
107 SoftwareAll,
109 SoftwareRecv,
111 #[default]
113 None,
114}
115
116impl From<GeneralTimestampMode> for InterfaceTimestampMode {
117 fn from(value: GeneralTimestampMode) -> Self {
118 match value {
119 GeneralTimestampMode::SoftwareAll => InterfaceTimestampMode::SoftwareAll,
120 GeneralTimestampMode::SoftwareRecv => InterfaceTimestampMode::SoftwareRecv,
121 GeneralTimestampMode::None => InterfaceTimestampMode::None,
122 }
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub struct RecvResult<A> {
129 pub bytes_read: usize,
131 pub remote_addr: A,
133 pub local_addr: A,
135 pub timestamp_data: TimestampData,
137}
138
139#[derive(Debug)]
141pub struct Socket<A, S> {
142 timestamp_mode: InterfaceTimestampMode,
143 raw: Arc<AsyncFd<RawSocket>>,
145 #[cfg(target_os = "linux")]
146 send_counter: std::sync::Mutex<u32>,
147 local_addr: A,
148 _state: PhantomData<S>,
149}
150
151#[non_exhaustive]
153pub struct Open;
154#[non_exhaustive]
156pub struct Connected;
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
160pub struct SendTimestampToken(u32);
161
162impl<A: NetworkAddress, S> Socket<A, S> {
163 pub fn local_addr(&self) -> A {
165 self.local_addr
166 }
167
168 fn inner_recv(&self, buf: &mut [u8], socket: &RawSocket) -> std::io::Result<RecvResult<A>> {
169 let mut control_buf = [0; EXPECTED_MAX_CMSG_SIZE];
170
171 let (bytes_read, control_messages, remote_address) =
173 socket.receive_message(buf, &mut control_buf, MessageQueue::Normal)?;
174
175 let mut timestamp_data = TimestampData::empty(self.timestamp_mode);
176 let mut local_addr = self.local_addr;
177
178 for msg in control_messages {
181 match msg {
182 ControlMessage::Timestamping { software, hardware } => {
183 tracing::trace!("Timestamps: {:?} {:?}", software, hardware);
184
185 timestamp_data.software = timestamp_data.software.or(software);
187 timestamp_data.hardware = timestamp_data.hardware.or(hardware);
188 }
189
190 #[cfg(target_os = "linux")]
191 ControlMessage::ReceiveError(error) => {
192 tracing::debug!(
193 "unexpected error control message on receive: {}",
194 error.ee_errno
195 );
196 }
197
198 ControlMessage::DestinationIp(addr) => {
199 if let Some(addr) = A::from_ip_and_port(addr, self.local_addr.port()) {
200 local_addr = addr;
201 }
202 }
203
204 ControlMessage::Other(msg) => {
205 tracing::debug!(
206 "unexpected control message on receive: {} {}",
207 msg.cmsg_level,
208 msg.cmsg_type,
209 );
210 }
211 }
212 }
213
214 let remote_addr =
215 A::from_sockaddr(remote_address, PrivateToken).ok_or(std::io::ErrorKind::Other)?;
216
217 Ok(RecvResult {
218 bytes_read,
219 remote_addr,
220 local_addr,
221 timestamp_data,
222 })
223 }
224
225 pub fn poll_recv(
231 &self,
232 buf: &mut [u8],
233 cx: &mut std::task::Context<'_>,
234 ) -> std::task::Poll<std::io::Result<RecvResult<A>>> {
235 loop {
239 match self.raw.poll_read_ready(cx) {
240 std::task::Poll::Ready(Ok(mut guard)) => {
241 if let Ok(result) = guard.try_io(|inner| self.inner_recv(buf, inner.get_ref()))
242 {
243 break std::task::Poll::Ready(result);
244 }
245 }
246 std::task::Poll::Ready(Err(e)) => break std::task::Poll::Ready(Err(e)),
247 std::task::Poll::Pending => break std::task::Poll::Pending,
248 }
249 }
250 }
251
252 pub async fn recv(&self, buf: &mut [u8]) -> std::io::Result<RecvResult<A>> {
258 self.raw
259 .async_io(Interest::READABLE, |socket| self.inner_recv(buf, socket))
260 .await
261 }
262
263 fn send_inner(
264 &self,
265 send_call: impl FnOnce() -> std::io::Result<()>,
266 ) -> std::io::Result<Option<SendTimestampToken>> {
267 if matches!(
268 self.timestamp_mode,
269 InterfaceTimestampMode::HardwareAll
270 | InterfaceTimestampMode::HardwarePTPAll
271 | InterfaceTimestampMode::SoftwareAll
272 ) {
273 #[cfg(target_os = "linux")]
274 {
275 let mut counter = self.send_counter.lock().unwrap();
276 send_call()?;
277 let token = SendTimestampToken(*counter);
278 *counter = counter.wrapping_add(1);
279 return Ok(Some(token));
280 }
281
282 #[cfg(not(target_os = "linux"))]
283 {
284 unreachable!("Should not be able to create send timestamping sockets on platforms other than linux")
285 }
286 }
287 send_call()?;
288 Ok(None)
289 }
290
291 pub fn get_send_timestamp(
302 &self,
303 ) -> impl std::future::Future<Output = std::io::Result<(SendTimestampToken, TimestampData)>>
304 + Send
305 + Sync
306 + 'static {
307 let timestamp_mode = self.timestamp_mode;
308 let socket = self.raw.clone();
309 async move {
310 if matches!(
311 timestamp_mode,
312 InterfaceTimestampMode::HardwareAll
313 | InterfaceTimestampMode::HardwarePTPAll
314 | InterfaceTimestampMode::SoftwareAll
315 ) {
316 #[cfg(target_os = "linux")]
317 {
318 let (counter, timestamp) = Self::fetch_send_timestamp(socket).await?;
319 return Ok((
320 SendTimestampToken(counter),
321 timestamp.with_timestamp_mode(timestamp_mode),
322 ));
323 }
324
325 #[cfg(not(target_os = "linux"))]
326 {
327 let _ = socket;
328 unreachable!("Should not be able to create send timestamping sockets on platforms other than linux")
329 }
330 }
331 Err(std::io::ErrorKind::Unsupported.into())
332 }
333 }
334
335 async fn send_timestamp_for_transmit(
342 &mut self,
343 token: SendTimestampToken,
344 ) -> std::io::Result<TimestampData> {
345 use std::time::Duration;
346
347 const TIMEOUT: Duration = Duration::from_millis(200);
348
349 tokio::time::timeout(TIMEOUT, async {
350 loop {
351 let (cur_token, timestamp_data) = self.get_send_timestamp().await?;
352 if cur_token == token {
353 return Ok(timestamp_data.with_timestamp_mode(self.timestamp_mode));
354 }
355 }
356 })
357 .await
358 .unwrap_or(Ok(TimestampData::empty(self.timestamp_mode)))
359 }
360}
361
362impl<A: NetworkAddress> Socket<A, Open> {
363 pub fn poll_send_to(
369 &self,
370 buf: &[u8],
371 addr: A,
372 cx: &mut std::task::Context<'_>,
373 ) -> std::task::Poll<std::io::Result<Option<SendTimestampToken>>> {
374 let addr = addr.to_sockaddr(PrivateToken);
375
376 loop {
380 match self.raw.poll_write_ready(cx) {
381 std::task::Poll::Ready(Ok(mut guard)) => {
382 if let Ok(result) =
383 guard.try_io(|inner| self.send_inner(|| inner.get_ref().send_to(buf, addr)))
384 {
385 break std::task::Poll::Ready(result);
386 }
387 }
388 std::task::Poll::Ready(Err(e)) => break std::task::Poll::Ready(Err(e)),
389 std::task::Poll::Pending => break std::task::Poll::Pending,
390 }
391 }
392 }
393
394 pub async fn send_to(&mut self, buf: &[u8], addr: A) -> std::io::Result<TimestampData> {
403 let addr = addr.to_sockaddr(PrivateToken);
404
405 if let Some(token) = self
406 .raw
407 .async_io(Interest::WRITABLE, |socket| {
408 self.send_inner(|| socket.send_to(buf, addr))
409 })
410 .await?
411 {
412 self.send_timestamp_for_transmit(token).await
413 } else {
414 Ok(TimestampData::empty(self.timestamp_mode))
415 }
416 }
417
418 pub fn poll_send_from_to(
424 &self,
425 buf: &[u8],
426 from: A,
427 to: A,
428 cx: &mut std::task::Context<'_>,
429 ) -> std::task::Poll<std::io::Result<Option<SendTimestampToken>>> {
430 let from = from.to_sockaddr(PrivateToken);
431 let to = to.to_sockaddr(PrivateToken);
432
433 loop {
437 match self.raw.poll_write_ready(cx) {
438 std::task::Poll::Ready(Ok(mut guard)) => {
439 if let Ok(result) = guard.try_io(|inner| {
440 self.send_inner(|| inner.get_ref().send_from_to(buf, from, to))
441 }) {
442 break std::task::Poll::Ready(result);
443 }
444 }
445 std::task::Poll::Ready(Err(e)) => break std::task::Poll::Ready(Err(e)),
446 std::task::Poll::Pending => break std::task::Poll::Pending,
447 }
448 }
449 }
450
451 pub async fn send_from_to(
460 &mut self,
461 buf: &[u8],
462 from: A,
463 to: A,
464 ) -> std::io::Result<TimestampData> {
465 let from = from.to_sockaddr(PrivateToken);
466 let to = to.to_sockaddr(PrivateToken);
467
468 if let Some(token) = self
469 .raw
470 .async_io(Interest::WRITABLE, |socket| {
471 self.send_inner(|| socket.send_from_to(buf, from, to))
472 })
473 .await?
474 {
475 self.send_timestamp_for_transmit(token).await
476 } else {
477 Ok(TimestampData::empty(self.timestamp_mode))
478 }
479 }
480
481 pub fn connect(self, addr: A) -> std::io::Result<Socket<A, Connected>> {
487 let addr = addr.to_sockaddr(PrivateToken);
488 self.raw.get_ref().connect(addr)?;
489 Ok(Socket {
490 timestamp_mode: self.timestamp_mode,
491 raw: self.raw,
492 #[cfg(target_os = "linux")]
493 send_counter: self.send_counter,
494 local_addr: self.local_addr,
495 _state: PhantomData,
496 })
497 }
498}
499
500impl<A: NetworkAddress> Socket<A, Connected> {
501 pub fn peer_addr(&self) -> std::io::Result<A> {
507 let addr = self.raw.get_ref().getpeername()?;
508 A::from_sockaddr(addr, PrivateToken).ok_or_else(|| std::io::ErrorKind::Other.into())
509 }
510
511 pub fn poll_send(
517 &self,
518 buf: &[u8],
519 cx: &mut std::task::Context<'_>,
520 ) -> std::task::Poll<std::io::Result<Option<SendTimestampToken>>> {
521 loop {
525 match self.raw.poll_write_ready(cx) {
526 std::task::Poll::Ready(Ok(mut guard)) => {
527 if let Ok(result) =
528 guard.try_io(|inner| self.send_inner(|| inner.get_ref().send(buf)))
529 {
530 break std::task::Poll::Ready(result);
531 }
532 }
533 std::task::Poll::Ready(Err(e)) => break std::task::Poll::Ready(Err(e)),
534 std::task::Poll::Pending => break std::task::Poll::Pending,
535 }
536 }
537 }
538
539 pub async fn send(&mut self, buf: &[u8]) -> std::io::Result<TimestampData> {
549 if let Some(token) = self
550 .raw
551 .async_io(Interest::WRITABLE, |socket| {
552 self.send_inner(|| socket.send(buf))
553 })
554 .await?
555 {
556 self.send_timestamp_for_transmit(token).await
557 } else {
558 Ok(TimestampData::empty(self.timestamp_mode))
559 }
560 }
561
562 pub fn poll_send_from(
568 &self,
569 buf: &[u8],
570 from: A,
571 cx: &mut std::task::Context<'_>,
572 ) -> std::task::Poll<std::io::Result<Option<SendTimestampToken>>> {
573 let from = from.to_sockaddr(PrivateToken);
574
575 loop {
579 match self.raw.poll_write_ready(cx) {
580 std::task::Poll::Ready(Ok(mut guard)) => {
581 if let Ok(result) = guard
582 .try_io(|inner| self.send_inner(|| inner.get_ref().send_from(buf, from)))
583 {
584 break std::task::Poll::Ready(result);
585 }
586 }
587 std::task::Poll::Ready(Err(e)) => break std::task::Poll::Ready(Err(e)),
588 std::task::Poll::Pending => break std::task::Poll::Pending,
589 }
590 }
591 }
592
593 pub async fn send_from(&mut self, buf: &[u8], from: A) -> std::io::Result<TimestampData> {
603 let from = from.to_sockaddr(PrivateToken);
604
605 if let Some(token) = self
606 .raw
607 .async_io(Interest::WRITABLE, |socket| {
608 self.send_inner(|| socket.send_from(buf, from))
609 })
610 .await?
611 {
612 self.send_timestamp_for_transmit(token).await
613 } else {
614 Ok(TimestampData::empty(self.timestamp_mode))
615 }
616 }
617}
618
619impl<A: MulticastJoinable, S> Socket<A, S> {
620 pub fn join_multicast(&self, addr: A, interface: InterfaceName) -> std::io::Result<()> {
625 addr.join_multicast(self.raw.get_ref().as_raw_fd(), interface, PrivateToken)
626 }
627
628 pub fn leave_multicast(&self, addr: A, interface: InterfaceName) -> std::io::Result<()> {
633 addr.leave_multicast(self.raw.get_ref().as_raw_fd(), interface, PrivateToken)
634 }
635}
636
637pub fn open_ip(
642 addr: SocketAddr,
643 timestamping: GeneralTimestampMode,
644 #[cfg_attr(not(target_os = "linux"), expect(unused))] reuse_addr: bool,
645) -> std::io::Result<Socket<SocketAddr, Open>> {
646 let socket = match addr {
648 SocketAddr::V4(_) => RawSocket::open(libc::PF_INET, libc::SOCK_DGRAM, libc::IPPROTO_UDP),
649 SocketAddr::V6(_) => RawSocket::open(libc::PF_INET6, libc::SOCK_DGRAM, libc::IPPROTO_UDP),
650 }?;
651 match addr {
652 SocketAddr::V4(_) => socket.enable_destination_ipv4()?,
653 SocketAddr::V6(_) => socket.enable_destination_ipv6()?,
654 }
655 #[cfg(target_os = "linux")]
656 if reuse_addr {
657 socket.reuse_addr()?;
658 }
659 socket.bind(addr.to_sockaddr(PrivateToken))?;
660 socket.set_nonblocking(true)?;
661 configure_timestamping(&socket, None, timestamping.into(), None)?;
662
663 let local_addr = SocketAddr::from_sockaddr(socket.getsockname()?, PrivateToken)
664 .ok_or::<std::io::Error>(std::io::ErrorKind::Other.into())?;
665
666 Ok(Socket {
669 timestamp_mode: timestamping.into(),
670 raw: Arc::new(unsafe { AsyncFd::register(socket) }?),
671 #[cfg(target_os = "linux")]
672 send_counter: std::sync::Mutex::new(0),
673 local_addr,
674 _state: PhantomData,
675 })
676}
677
678pub fn open_ipv4(
683 addr: SocketAddrV4,
684 timestamping: GeneralTimestampMode,
685 #[cfg_attr(not(target_os = "linux"), expect(unused))] reuse_addr: bool,
686) -> std::io::Result<Socket<SocketAddrV4, Open>> {
687 let socket = RawSocket::open(libc::PF_INET, libc::SOCK_DGRAM, libc::IPPROTO_UDP)?;
689 socket.enable_destination_ipv4()?;
690 #[cfg(target_os = "linux")]
691 if reuse_addr {
692 socket.reuse_addr()?;
693 }
694 socket.bind(addr.to_sockaddr(PrivateToken))?;
695 socket.set_nonblocking(true)?;
696 configure_timestamping(&socket, None, timestamping.into(), None)?;
697
698 let local_addr = SocketAddrV4::from_sockaddr(socket.getsockname()?, PrivateToken)
699 .ok_or::<std::io::Error>(std::io::ErrorKind::Other.into())?;
700
701 Ok(Socket {
704 timestamp_mode: timestamping.into(),
705 raw: Arc::new(unsafe { AsyncFd::register(socket) }?),
706 #[cfg(target_os = "linux")]
707 send_counter: std::sync::Mutex::new(0),
708 local_addr,
709 _state: PhantomData,
710 })
711}
712
713pub fn open_ipv6(
718 addr: SocketAddrV6,
719 timestamping: GeneralTimestampMode,
720 #[cfg_attr(not(target_os = "linux"), expect(unused))] reuse_addr: bool,
721) -> std::io::Result<Socket<SocketAddrV6, Open>> {
722 let socket = RawSocket::open(libc::PF_INET6, libc::SOCK_DGRAM, libc::IPPROTO_UDP)?;
724 socket.ipv6_only()?;
725 socket.enable_destination_ipv6()?;
726 #[cfg(target_os = "linux")]
727 if reuse_addr {
728 socket.reuse_addr()?;
729 }
730 socket.bind(addr.to_sockaddr(PrivateToken))?;
731 socket.set_nonblocking(true)?;
732 configure_timestamping(&socket, None, timestamping.into(), None)?;
733
734 let local_addr = SocketAddrV6::from_sockaddr(socket.getsockname()?, PrivateToken)
735 .ok_or::<std::io::Error>(std::io::ErrorKind::Other.into())?;
736
737 Ok(Socket {
740 timestamp_mode: timestamping.into(),
741 raw: Arc::new(unsafe { AsyncFd::register(socket) }?),
742 #[cfg(target_os = "linux")]
743 send_counter: std::sync::Mutex::new(0),
744 local_addr,
745 _state: PhantomData,
746 })
747}
748
749pub fn connect_address(
754 addr: SocketAddr,
755 timestamping: GeneralTimestampMode,
756) -> std::io::Result<Socket<SocketAddr, Connected>> {
757 let socket = match addr {
759 SocketAddr::V4(_) => RawSocket::open(libc::PF_INET, libc::SOCK_DGRAM, libc::IPPROTO_UDP),
760 SocketAddr::V6(_) => RawSocket::open(libc::PF_INET6, libc::SOCK_DGRAM, libc::IPPROTO_UDP),
761 }?;
762 match addr {
763 SocketAddr::V4(_) => socket.enable_destination_ipv4()?,
764 SocketAddr::V6(_) => socket.enable_destination_ipv6()?,
765 }
766 socket.connect(addr.to_sockaddr(PrivateToken))?;
767 socket.set_nonblocking(true)?;
768 configure_timestamping(&socket, None, timestamping.into(), None)?;
769
770 let local_addr = SocketAddr::from_sockaddr(socket.getsockname()?, PrivateToken)
771 .ok_or::<std::io::Error>(std::io::ErrorKind::Other.into())?;
772
773 Ok(Socket {
776 timestamp_mode: timestamping.into(),
777 raw: Arc::new(unsafe { AsyncFd::register(socket) }?),
778 #[cfg(target_os = "linux")]
779 send_counter: std::sync::Mutex::new(0),
780 local_addr,
781 _state: PhantomData,
782 })
783}
784
785#[cfg(test)]
786mod tests {
787 use super::*;
788 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
789
790 #[tokio::test]
791 async fn test_open_ip() {
792 let mut a = open_ip(
793 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5125),
794 GeneralTimestampMode::None,
795 false,
796 )
797 .unwrap();
798 let mut b = connect_address(
799 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5125),
800 GeneralTimestampMode::None,
801 )
802 .unwrap();
803 assert!(b.send(&[1, 2, 3]).await.is_ok());
804 let mut buf = [0; 4];
805 let recv_result = a.recv(&mut buf).await.unwrap();
806 assert_eq!(recv_result.bytes_read, 3);
807 assert_eq!(&buf[0..3], &[1, 2, 3]);
808 assert!(a.send_to(&[4, 5, 6], recv_result.remote_addr).await.is_ok());
809 let recv_result = b.recv(&mut buf).await.unwrap();
810 assert_eq!(recv_result.bytes_read, 3);
811 assert_eq!(&buf[0..3], &[4, 5, 6]);
812 }
813
814 #[tokio::test]
815 async fn test_open_ip_dest_addr() {
816 let a = open_ip(
817 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 5127),
818 GeneralTimestampMode::None,
819 false,
820 )
821 .unwrap();
822 let mut b = connect_address(
823 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5127),
824 GeneralTimestampMode::None,
825 )
826 .unwrap();
827 assert!(b.send(&[1, 2, 3]).await.is_ok());
828 let mut buf = [0; 4];
829 let recv_result = a.recv(&mut buf).await.unwrap();
830 assert_eq!(recv_result.bytes_read, 3);
831 assert_eq!(&buf[0..3], &[1, 2, 3]);
832 assert_eq!(
833 recv_result.local_addr,
834 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5127)
835 );
836 assert_ne!(a.local_addr().ip(), IpAddr::V4(Ipv4Addr::LOCALHOST));
837
838 let a = open_ip(
839 SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 5129),
840 GeneralTimestampMode::None,
841 false,
842 )
843 .unwrap();
844 let mut b = connect_address(
845 SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 5129),
846 GeneralTimestampMode::None,
847 )
848 .unwrap();
849 assert!(b.send(&[1, 2, 3]).await.is_ok());
850 let mut buf = [0; 4];
851 let recv_result = a.recv(&mut buf).await.unwrap();
852 assert_eq!(recv_result.bytes_read, 3);
853 assert_eq!(&buf[0..3], &[1, 2, 3]);
854 assert_eq!(
855 recv_result.local_addr,
856 SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 5129)
857 );
858 assert_ne!(a.local_addr().ip(), IpAddr::V6(Ipv6Addr::LOCALHOST));
859 }
860
861 #[tokio::test]
862 async fn test_send_from() {
863 let mut a = open_ip(
864 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 5130),
865 GeneralTimestampMode::None,
866 false,
867 )
868 .unwrap();
869 let mut b = connect_address(
870 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5130),
871 GeneralTimestampMode::None,
872 )
873 .unwrap();
874 b.send_from(
875 &[1, 2, 3],
876 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0),
877 )
878 .await
879 .unwrap();
880 let mut buf = [0; 4];
881 let recv_result = a.recv(&mut buf).await.unwrap();
882 assert_eq!(recv_result.bytes_read, 3);
883 assert_eq!(&buf[0..3], &[1, 2, 3]);
884 assert_eq!(
885 recv_result.remote_addr.ip(),
886 IpAddr::V4(Ipv4Addr::LOCALHOST)
887 );
888
889 a.send_from_to(
890 &[1, 2, 3],
891 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0),
892 dbg!(b.local_addr()),
893 )
894 .await
895 .unwrap();
896 let mut buf = [0; 4];
897 let recv_result = b.recv(&mut buf).await.unwrap();
898 assert_eq!(recv_result.bytes_read, 3);
899 assert_eq!(&buf[0..3], &[1, 2, 3]);
900 assert_eq!(
901 recv_result.remote_addr.ip(),
902 IpAddr::V4(Ipv4Addr::LOCALHOST)
903 );
904 }
905
906 #[tokio::test]
907 async fn test_send_from_v6() {
908 let mut a = open_ip(
909 SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 5131),
910 GeneralTimestampMode::None,
911 false,
912 )
913 .unwrap();
914 let mut b = connect_address(
915 SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 5131),
916 GeneralTimestampMode::None,
917 )
918 .unwrap();
919 b.send_from(
920 &[1, 2, 3],
921 SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 0),
922 )
923 .await
924 .unwrap();
925 let mut buf = [0; 4];
926 let recv_result = a.recv(&mut buf).await.unwrap();
927 assert_eq!(recv_result.bytes_read, 3);
928 assert_eq!(&buf[0..3], &[1, 2, 3]);
929 assert_eq!(
930 recv_result.remote_addr.ip(),
931 IpAddr::V6(Ipv6Addr::LOCALHOST)
932 );
933
934 a.send_from_to(
935 &[1, 2, 3],
936 SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 0),
937 dbg!(b.local_addr()),
938 )
939 .await
940 .unwrap();
941 let mut buf = [0; 4];
942 let recv_result = b.recv(&mut buf).await.unwrap();
943 assert_eq!(recv_result.bytes_read, 3);
944 assert_eq!(&buf[0..3], &[1, 2, 3]);
945 assert_eq!(
946 recv_result.remote_addr.ip(),
947 IpAddr::V6(Ipv6Addr::LOCALHOST)
948 );
949 }
950}