async_coap/datagram/async_socket.rs
1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use super::*;
17use futures::prelude::*;
18use futures::task::Context;
19use futures::Poll;
20use std::pin::Pin;
21
22/// A trait for asynchronous datagram sockets.
23///
24/// This is an empty convenience trait that requires several additional traits to be implemented:
25/// [`DatagramSocketTypes`], [`AsyncSendTo`], [`AsyncRecvFrom`], [`MulticastSocket`],
26/// and [`Send`]+[`Sync`].
27///
28/// Implementations of this trait can be used with [`DatagramLocalEndpoint`].
29pub trait AsyncDatagramSocket:
30 DatagramSocketTypes + AsyncSendTo + AsyncRecvFrom + MulticastSocket + Send + Sync
31{
32}
33
34/// Trait implemented by a "socket" that describes the underlying `SocketAddr` and socket error
35/// types as associated types.
36pub trait DatagramSocketTypes: Unpin {
37 /// The "`SocketAddr`" type used by this "socket". Typically [`std::net::SocketAddr`].
38 type SocketAddr: SocketAddrExt
39 + core::fmt::Display
40 + core::fmt::Debug
41 + std::string::ToString
42 + ToSocketAddrs<SocketAddr = Self::SocketAddr, Error = Self::Error>
43 + Send
44 + Unpin
45 + Copy;
46
47 /// The error type for errors emitted from this socket. Typically [`std::io::Error`].
48 type Error: std::fmt::Display + std::fmt::Debug;
49
50 /// Returns the local `SocketAddr` of this "socket".
51 fn local_addr(&self) -> Result<Self::SocketAddr, Self::Error>;
52
53 /// Performs a blocking hostname lookup.
54 fn lookup_host(
55 host: &str,
56 port: u16,
57 ) -> Result<std::vec::IntoIter<Self::SocketAddr>, Self::Error>
58 where
59 Self: Sized;
60}
61
62/// Trait for providing `sent_to` functionality for asynchronous, datagram-based sockets.
63pub trait AsyncSendTo: DatagramSocketTypes {
64 /// A non-blocking[^1], `poll_*` version of `std::net::UdpSocket::send_to`.
65 ///
66 /// [^1]: Note that while the spirit of this method intends for it to be non-blocking,
67 /// [`AllowStdUdpSocket`] can block execution depending on the implementation details
68 /// of the underlying [`std::net::UdpSocket`].
69 fn poll_send_to<B>(
70 self: Pin<&Self>,
71 cx: &mut Context<'_>,
72 buf: &[u8],
73 addr: B,
74 ) -> Poll<Result<usize, Self::Error>>
75 where
76 B: super::ToSocketAddrs<SocketAddr = Self::SocketAddr, Error = Self::Error>;
77
78 /// Returns a future that uses [`AsyncSendTo::poll_send_to`].
79 fn next_send_to<'a, 'b, B>(&'a self, buf: &'b [u8], addr: B) -> NextSendToFuture<'a, 'b, Self>
80 where
81 B: super::ToSocketAddrs<SocketAddr = Self::SocketAddr, Error = Self::Error>,
82 {
83 let addr = addr.to_socket_addrs().unwrap().next().unwrap();
84 NextSendToFuture {
85 socket: self,
86 buffer: buf,
87 addr: addr,
88 }
89 }
90
91 /// A *synchronous* version of [`AsyncSendTo::poll_send_to`]. If this isn't overridden by the
92 /// trait's implementation, the default version will call `poll_send_to()` and panics if it
93 /// returns `Poll::Pending`.
94 fn send_to<B>(&self, buf: &[u8], addr: B) -> Result<usize, Self::Error>
95 where
96 B: super::ToSocketAddrs<SocketAddr = Self::SocketAddr, Error = Self::Error>,
97 {
98 self.next_send_to(buf, addr)
99 .now_or_never()
100 .expect("send_to blocked")
101 }
102}
103
104/// Future returned from [`AsyncSendTo::next_send_to`].
105#[derive(Debug)]
106pub struct NextSendToFuture<'a, 'b, T>
107where
108 T: DatagramSocketTypes + AsyncSendTo + ?Sized,
109{
110 socket: &'a T,
111 buffer: &'b [u8],
112 addr: T::SocketAddr,
113}
114
115impl<'a, 'b, T> NextSendToFuture<'a, 'b, T>
116where
117 T: DatagramSocketTypes + AsyncSendTo + ?Sized,
118{
119 fn poll_unpin(
120 self: &mut Self,
121 cx: &mut futures::task::Context<'_>,
122 ) -> futures::task::Poll<Result<usize, T::Error>> {
123 Pin::new(self.socket).poll_send_to(cx, self.buffer, self.addr.clone())
124 }
125}
126
127impl<'a, 'b, T> Future for NextSendToFuture<'a, 'b, T>
128where
129 T: DatagramSocketTypes + AsyncSendTo + ?Sized,
130{
131 type Output = Result<usize, T::Error>;
132
133 fn poll(
134 self: Pin<&mut Self>,
135 cx: &mut futures::task::Context<'_>,
136 ) -> futures::task::Poll<Self::Output> {
137 self.get_mut().poll_unpin(cx)
138 }
139}
140
141/// Future returned from [`AsyncRecvFrom::next_recv_from`].
142#[derive(Debug)]
143pub struct NextRecvFromFuture<'a, 'b, T: AsyncRecvFrom + ?Sized> {
144 socket: &'a T,
145 buffer: &'b mut [u8],
146}
147
148impl<'a, 'b, T: AsyncRecvFrom + ?Sized + Unpin> NextRecvFromFuture<'a, 'b, T> {
149 fn poll_unpin(
150 self: &mut Self,
151 cx: &mut futures::task::Context<'_>,
152 ) -> futures::task::Poll<Result<(usize, T::SocketAddr, Option<T::SocketAddr>), T::Error>> {
153 Pin::new(self.socket).poll_recv_from(cx, self.buffer)
154 }
155}
156
157impl<'a, 'b, T: AsyncRecvFrom + ?Sized> Future for NextRecvFromFuture<'a, 'b, T> {
158 type Output = Result<(usize, T::SocketAddr, Option<T::SocketAddr>), T::Error>;
159
160 fn poll(
161 self: Pin<&mut Self>,
162 cx: &mut futures::task::Context<'_>,
163 ) -> futures::task::Poll<Self::Output> {
164 self.get_mut().poll_unpin(cx)
165 }
166}
167
168/// Trait for providing `recv_from` functionality for asynchronous, datagram-based sockets.
169///
170/// The value returned on success is a tuple of the following:
171///
172/// ```
173/// # use std::net::SocketAddr;
174/// # fn ignore_this_line
175/// #
176/// (bytes_written: usize,
177/// remote_socket_addr: SocketAddr,
178/// local_socket_addr: Option<SocketAddr>)
179/// #
180/// # {} // ignore this line
181/// ```
182///
183/// `local_socket_addr` indicates the local address that the packet was sent to, and may not be
184/// supported. If this isn't supported, `local_socket_addr` will be set to `None`.
185pub trait AsyncRecvFrom: DatagramSocketTypes {
186 /// A non-blocking[^1], `poll_*` version of [`std::net::UdpSocket::recv_from`] that can
187 /// optionally provide the destination (local) `SocketAddr`.
188 ///
189 /// If you need to receive a packet from within an async block, see
190 /// [`AsyncRecvFrom::next_recv_from`], which returns a [`Future`][std::future::Future].
191 ///
192 /// [^1]: Note that while the spirit of this method intends for it to be non-blocking,
193 /// [`AllowStdUdpSocket`] can in fact block execution depending on the state of the
194 /// underlying [`std::net::UdpSocket`].
195 fn poll_recv_from(
196 self: Pin<&Self>,
197 cx: &mut Context<'_>,
198 buf: &mut [u8],
199 ) -> Poll<Result<(usize, Self::SocketAddr, Option<Self::SocketAddr>), Self::Error>>;
200
201 /// Returns a future that uses [`poll_recv_from`][AsyncRecvFrom::poll_recv_from].
202 fn next_recv_from<'a, 'b>(&'a self, buf: &'b mut [u8]) -> NextRecvFromFuture<'a, 'b, Self> {
203 NextRecvFromFuture {
204 socket: self,
205 buffer: buf,
206 }
207 }
208}
209
210/// Trait that provides methods for joining/leaving multicast groups.
211pub trait MulticastSocket: DatagramSocketTypes {
212 /// The "address" type for this socket.
213 ///
214 /// Note that this is different than a `SocketAddr`, which also includes a port number.
215 /// This is just the address.
216 type IpAddr;
217
218 /// Attempts to join the given multicast group.
219 fn join_multicast<A>(&self, addr: A) -> Result<(), Self::Error>
220 where
221 A: std::convert::Into<Self::IpAddr>;
222
223 /// Attempts to leave the given multicast group.
224 fn leave_multicast<A>(&self, addr: A) -> Result<(), Self::Error>
225 where
226 A: std::convert::Into<Self::IpAddr>;
227}