async_coap/socketaddr.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 std::hash::Hash;
18
19/// A flavor of `std::net::ToSocketAddrs` that allows the implementation of
20/// `SocketAddr` to be replaced.
21///
22/// This is necessary to enable support for things like
23/// CoAP-over-SMS, where socket addresses are telephone numbers.
24pub trait ToSocketAddrs {
25 /// Analogous to [`std::net::ToSocketAddrs::Iter`]
26 type Iter: Iterator<Item = Self::SocketAddr>;
27
28 /// The `SocketAddr` type returned by the above iterator.
29 type SocketAddr: SocketAddrExt + Copy;
30
31 /// The error type to use for errors while resolving.
32 type Error: core::fmt::Debug;
33
34 /// Analogous to [`std::net::ToSocketAddrs::to_socket_addrs`]
35 fn to_socket_addrs(&self) -> Result<Self::Iter, Self::Error>;
36}
37
38/// Blanket implementation of `ToSocketAddrs` for all implementations of `std::net::ToSocketAddrs`.
39#[cfg(feature = "std")]
40impl<T, I> ToSocketAddrs for T
41where
42 T: std::net::ToSocketAddrs<Iter = I>,
43 I: Iterator<Item = std::net::SocketAddr>,
44{
45 type Iter = I;
46 type SocketAddr = std::net::SocketAddr;
47 type Error = std::io::Error;
48
49 fn to_socket_addrs(&self) -> Result<Self::Iter, Self::Error> {
50 std::net::ToSocketAddrs::to_socket_addrs(self)
51 }
52}
53
54/// Extension trait for `SocketAddr` types that allows the local endpoint get the information
55/// it needs.
56pub trait SocketAddrExt:
57 Sized + ToSocketAddrs + Copy + core::fmt::Display + core::fmt::Debug + Send + Eq + Hash
58{
59 /// Determines if the address in this `SocketAddr` is a multicast/broadcast address or not.
60 fn is_multicast(&self) -> bool;
61
62 /// Returns the port number for this socket.
63 ///
64 /// A value of zero indicates no specific value.
65 fn port(&self) -> u16;
66
67 /// Returns a version of this socket address that conforms to the address type of `local`,
68 /// or `None` if such a conversion is not possible.
69 ///
70 /// This method is useful in mixed ipv6/ipv4 environments.
71 #[allow(unused_variables)]
72 fn conforming_to(&self, local: Self) -> Option<Self> {
73 Some(*self)
74 }
75
76 /// Renders the address portion to a string.
77 fn addr_to_string(&self) -> String;
78
79 /// Creates a URI from this `SocketAddr` using the given scheme.
80 fn as_uri_buf(&self, scheme: &str) -> UriBuf {
81 UriBuf::from_scheme_host_port(scheme, self.addr_to_string(), Some(self.port()))
82 }
83}
84
85#[cfg(feature = "std")]
86impl SocketAddrExt for std::net::SocketAddr {
87 fn is_multicast(&self) -> bool {
88 self.ip().is_multicast()
89 || if let std::net::IpAddr::V4(addr) = self.ip() {
90 addr.is_broadcast()
91 } else {
92 false
93 }
94 }
95
96 fn port(&self) -> u16 {
97 self.port()
98 }
99
100 fn conforming_to(&self, local: Self) -> Option<Self> {
101 if self.is_ipv6() == local.is_ipv6() {
102 Some(*self)
103 } else if let std::net::SocketAddr::V4(v4) = self {
104 Some((v4.ip().to_ipv6_mapped(), v4.port()).into())
105 } else {
106 None
107 }
108 }
109
110 fn addr_to_string(&self) -> String {
111 self.ip().to_string()
112 }
113
114 fn as_uri_buf(&self, scheme: &str) -> UriBuf {
115 UriBuf::from_scheme_host_port(scheme, self.ip().to_string(), Some(self.port()))
116 }
117}