dns/
udp.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::FuchsiaTime;
6use async_trait::async_trait;
7use fuchsia_async::net::UdpSocket;
8use futures::FutureExt as _;
9use std::io;
10use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
11use std::pin::pin;
12use std::task::{Context, Poll};
13use trust_dns_proto::udp;
14
15/// A Fuchsia-compatible implementation of trust-dns's `UdpSocket` trait which allows
16/// creating a UdpSocket to a particular destination.
17pub struct DnsUdpSocket(UdpSocket);
18
19#[async_trait]
20impl udp::UdpSocket for DnsUdpSocket {
21    type Time = FuchsiaTime;
22
23    async fn connect_with_bind(_addr: SocketAddr, bind_addr: SocketAddr) -> io::Result<Self> {
24        let socket = Self::bind(bind_addr).await?;
25
26        // TODO(https://fxbug.dev/42060217): Consider calling connect on the
27        // socket. Doing so isn't strictly necessary and is disabled within the
28        // provided Trust-DNS implementations. As a result, the same behavior is
29        // currently implemented here. See
30        // https://github.com/bluejekyll/trust-dns/commit/e712a2c031572a128d720d6c763a83fe57399d7f
31
32        Ok(socket)
33    }
34
35    async fn connect(addr: SocketAddr) -> io::Result<Self> {
36        let bind_addr = match addr {
37            SocketAddr::V4(_addr) => (Ipv4Addr::UNSPECIFIED, 0).into(),
38            SocketAddr::V6(_addr) => (Ipv6Addr::UNSPECIFIED, 0).into(),
39        };
40
41        Self::connect_with_bind(addr, bind_addr).await
42    }
43
44    async fn bind(addr: SocketAddr) -> io::Result<Self> {
45        UdpSocket::bind(&addr).map(Self)
46    }
47
48    fn poll_recv_from(
49        &self,
50        cx: &mut Context<'_>,
51        buf: &mut [u8],
52    ) -> Poll<io::Result<(usize, SocketAddr)>> {
53        let fut = self.recv_from(buf);
54        let mut fut = pin!(fut);
55        fut.poll_unpin(cx)
56    }
57
58    async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
59        let Self(socket) = self;
60        socket.recv_from(buf).await
61    }
62
63    fn poll_send_to(
64        &self,
65        cx: &mut Context<'_>,
66        buf: &[u8],
67        target: SocketAddr,
68    ) -> Poll<io::Result<usize>> {
69        let fut = self.send_to(buf, target);
70        let mut fut = pin!(fut);
71        fut.poll_unpin(cx)
72    }
73
74    async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
75        let Self(socket) = self;
76        socket.send_to(buf, target).await
77    }
78}
79
80#[cfg(test)]
81mod test {
82    use super::*;
83    use crate::FuchsiaExec;
84
85    use net_declare::std::ip;
86
87    #[test]
88    fn test_next_random_socket() {
89        use trust_dns_proto::tests::next_random_socket_test;
90        let exec = FuchsiaExec::new().expect("failed to create fuchsia executor");
91        next_random_socket_test::<DnsUdpSocket, FuchsiaExec>(exec)
92    }
93
94    #[fuchsia_async::run_singlethreaded(test)]
95    async fn test_udp_stream_ipv4() {
96        use trust_dns_proto::tests::udp_stream_test;
97        udp_stream_test::<DnsUdpSocket>(ip!("127.0.0.1")).await
98    }
99
100    #[fuchsia_async::run_singlethreaded(test)]
101    async fn test_udp_stream_ipv6() {
102        use trust_dns_proto::tests::udp_stream_test;
103        udp_stream_test::<DnsUdpSocket>(ip!("::1")).await
104    }
105
106    #[test]
107    fn test_udp_client_stream_ipv4() {
108        use trust_dns_proto::tests::udp_client_stream_test;
109        let exec = FuchsiaExec::new().expect("failed to create fuchsia executor");
110        udp_client_stream_test::<DnsUdpSocket, FuchsiaExec, FuchsiaTime>(ip!("127.0.0.1"), exec)
111    }
112
113    #[test]
114    fn test_udp_client_stream_ipv6() {
115        use trust_dns_proto::tests::udp_client_stream_test;
116        let exec = FuchsiaExec::new().expect("failed to create fuchsia executor");
117        udp_client_stream_test::<DnsUdpSocket, FuchsiaExec, FuchsiaTime>(ip!("::1"), exec)
118    }
119}