hickory_proto/multicast/
mdns_client_stream.rs

1// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use alloc::boxed::Box;
9use core::fmt::{self, Display};
10use core::future::Future;
11use core::pin::Pin;
12use core::task::{Context, Poll};
13use std::net::{Ipv4Addr, SocketAddr};
14
15use futures_util::future::{FutureExt, TryFutureExt};
16use futures_util::stream::{Stream, StreamExt, TryStreamExt};
17
18use crate::BufDnsStreamHandle;
19use crate::error::ProtoError;
20use crate::multicast::mdns_stream::{MDNS_IPV4, MDNS_IPV6};
21use crate::multicast::{MdnsQueryType, MdnsStream};
22use crate::runtime::TokioTime;
23use crate::xfer::{DnsClientStream, SerialMessage};
24
25/// A UDP client stream of DNS binary packets
26#[must_use = "futures do nothing unless polled"]
27pub struct MdnsClientStream {
28    mdns_stream: MdnsStream,
29}
30
31impl MdnsClientStream {
32    /// associates the socket to the well-known ipv4 multicast address
33    pub fn new_ipv4(
34        mdns_query_type: MdnsQueryType,
35        packet_ttl: Option<u32>,
36        ipv4_if: Option<Ipv4Addr>,
37    ) -> (MdnsClientConnect, BufDnsStreamHandle) {
38        Self::new(*MDNS_IPV4, mdns_query_type, packet_ttl, ipv4_if, None)
39    }
40
41    /// associates the socket to the well-known ipv6 multicast address
42    pub fn new_ipv6(
43        mdns_query_type: MdnsQueryType,
44        packet_ttl: Option<u32>,
45        ipv6_if: Option<u32>,
46    ) -> (MdnsClientConnect, BufDnsStreamHandle) {
47        Self::new(*MDNS_IPV6, mdns_query_type, packet_ttl, None, ipv6_if)
48    }
49
50    /// it is expected that the resolver wrapper will be responsible for creating and managing
51    ///  new UdpClients such that each new client would have a random port (reduce chance of cache
52    ///  poisoning)
53    ///
54    /// # Return
55    ///
56    /// a tuple of a Future Stream which will handle sending and receiving messages, and a
57    ///  handle which can be used to send messages into the stream.
58    #[allow(clippy::new_ret_no_self)]
59    pub fn new(
60        mdns_addr: SocketAddr,
61        mdns_query_type: MdnsQueryType,
62        packet_ttl: Option<u32>,
63        ipv4_if: Option<Ipv4Addr>,
64        ipv6_if: Option<u32>,
65    ) -> (MdnsClientConnect, BufDnsStreamHandle) {
66        let (stream_future, sender) =
67            MdnsStream::new(mdns_addr, mdns_query_type, packet_ttl, ipv4_if, ipv6_if);
68
69        let stream_future = stream_future
70            .map_ok(move |mdns_stream| Self { mdns_stream })
71            .map_err(ProtoError::from);
72
73        let new_future = Box::new(stream_future);
74        let new_future = MdnsClientConnect(new_future);
75
76        (new_future, sender)
77    }
78}
79
80impl Display for MdnsClientStream {
81    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
82        write!(formatter, "mDNS({})", self.mdns_stream.multicast_addr())
83    }
84}
85
86impl DnsClientStream for MdnsClientStream {
87    type Time = TokioTime;
88
89    fn name_server_addr(&self) -> SocketAddr {
90        self.mdns_stream.multicast_addr()
91    }
92}
93
94impl Stream for MdnsClientStream {
95    type Item = Result<SerialMessage, ProtoError>;
96
97    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
98        let mdns_stream = &mut self.as_mut().mdns_stream;
99        mdns_stream.map_err(ProtoError::from).poll_next_unpin(cx)
100        // match ready!(self.mdns_stream.poll_next_unpin(cx).map_err(ProtoError::from)) {
101        //     Some(serial_message) => {
102        //         // TODO: for mDNS queries could come from anywhere. It's not clear that there is anything
103        //         //       we can validate in this case.
104        //         Poll::Ready(Some(Ok(serial_message)))
105        //     }
106        //     None => Poll::Ready(None),
107        // }
108    }
109}
110
111/// A future that resolves to an MdnsClientStream
112pub struct MdnsClientConnect(
113    Box<dyn Future<Output = Result<MdnsClientStream, ProtoError>> + Send + Unpin>,
114);
115
116impl Future for MdnsClientConnect {
117    type Output = Result<MdnsClientStream, ProtoError>;
118
119    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
120        self.0.as_mut().poll_unpin(cx)
121    }
122}