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