no-std-net-0.6.0/.cargo_vcs_info.json0000644000000001120000000000100130210ustar { "git": { "sha1": "19e2b9405b6193014007e1c177efd33ae0bf5052" } } no-std-net-0.6.0/.gitignore000064400000000000000000000004630072674642500136420ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk no-std-net-0.6.0/.travis.yml000064400000000000000000000002740072674642500137630ustar 00000000000000language: rust rust: - stable - beta - nightly cache: cargo script: - cargo test --verbose - cargo build --features serde - cargo test --features std - cargo test --features unstable_ip no-std-net-0.6.0/Cargo.toml0000644000000020410000000000100110220ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "no-std-net" version = "0.6.0" authors = ["M@ Dunlap "] description = "Rust's std::net... without the 'std'." readme = "README.md" categories = ["embedded", "network-programming", "no-std"] license = "MIT" repository = "https://github.com/dunmatt/no-std-net" [dependencies.serde] version = "^1" optional = true default-features = false [dev-dependencies.serde_test] version = "^1" [features] i128 = [] std = [] unstable_ip = [] [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "dunmatt/no-std-net" no-std-net-0.6.0/Cargo.toml.orig000064400000000000000000000014010072674642500145320ustar 00000000000000[package] name = "no-std-net" description = "Rust's std::net... without the 'std'." version = "0.6.0" authors = ["M@ Dunlap "] categories = [ "embedded", "network-programming", "no-std", ] repository = "https://github.com/dunmatt/no-std-net" edition = "2018" license = "MIT" readme = "README.md" [badges] maintenance = { status = "actively-developed" } travis-ci = { repository = "dunmatt/no-std-net" } [dependencies] serde = { version = "^1", default-features = false, optional = true } [dev-dependencies] serde_test = "^1" [features] # Makes the library act as a facade to std::net types std = [] # Like `#![feature(ip)]`, see https://github.com/rust-lang/rust/issues/27709 unstable_ip = [] # Deprecated. Does nothing. i128 = [] no-std-net-0.6.0/LICENSE000064400000000000000000000020430072674642500126530ustar 00000000000000MIT License Copyright (c) 2018 M@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. no-std-net-0.6.0/README.md000064400000000000000000000000650072674642500131270ustar 00000000000000# no-std-net Rust's std::net except without the std. no-std-net-0.6.0/src/addr/tests.rs000064400000000000000000000125250072674642500150650ustar 00000000000000use crate::test::tsa; use crate::*; #[test] fn to_socket_addr_ipaddr_u16() { let a = Ipv4Addr::new(77, 88, 21, 11); let p = 12345; let e = SocketAddr::V4(SocketAddrV4::new(a, p)); assert_eq!(Ok(vec![e]), tsa((a, p))); } #[test] fn set_ip() { fn ip4(low: u8) -> Ipv4Addr { Ipv4Addr::new(77, 88, 21, low) } fn ip6(low: u16) -> Ipv6Addr { Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) } let mut v4 = SocketAddrV4::new(ip4(11), 80); assert_eq!(v4.ip(), &ip4(11)); v4.set_ip(ip4(12)); assert_eq!(v4.ip(), &ip4(12)); let mut addr = SocketAddr::V4(v4); assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); addr.set_ip(IpAddr::V4(ip4(13))); assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); addr.set_ip(IpAddr::V6(ip6(14))); assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); assert_eq!(v6.ip(), &ip6(1)); v6.set_ip(ip6(2)); assert_eq!(v6.ip(), &ip6(2)); let mut addr = SocketAddr::V6(v6); assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); addr.set_ip(IpAddr::V6(ip6(3))); assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); addr.set_ip(IpAddr::V4(ip4(4))); assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); } #[test] fn set_port() { let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); assert_eq!(v4.port(), 80); v4.set_port(443); assert_eq!(v4.port(), 443); let mut addr = SocketAddr::V4(v4); assert_eq!(addr.port(), 443); addr.set_port(8080); assert_eq!(addr.port(), 8080); let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); assert_eq!(v6.port(), 80); v6.set_port(443); assert_eq!(v6.port(), 443); let mut addr = SocketAddr::V6(v6); assert_eq!(addr.port(), 443); addr.set_port(8080); assert_eq!(addr.port(), 8080); } #[test] fn set_flowinfo() { let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); assert_eq!(v6.flowinfo(), 10); v6.set_flowinfo(20); assert_eq!(v6.flowinfo(), 20); } #[test] fn set_scope_id() { let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); assert_eq!(v6.scope_id(), 10); v6.set_scope_id(20); assert_eq!(v6.scope_id(), 20); } #[test] fn is_v4() { let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); assert!(v4.is_ipv4()); assert!(!v4.is_ipv6()); } #[test] fn is_v6() { let v6 = SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0, )); assert!(!v6.is_ipv4()); assert!(v6.is_ipv6()); } #[test] fn socket_v4_to_str() { let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); assert_eq!(format!("{}", socket), "192.168.0.1:8080"); assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 "); assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); assert_eq!(format!("{:.10}", socket), "192.168.0."); } #[test] fn socket_v6_to_str() { let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); socket.set_scope_id(5); assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1%5]:53"); assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53 "); assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1%5]:53"); assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 "); assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%5"); } #[test] fn compare() { let v4_1 = "224.120.45.1:23456".parse::().unwrap(); let v4_2 = "224.210.103.5:12345".parse::().unwrap(); let v4_3 = "224.210.103.5:23456".parse::().unwrap(); let v6_1 = "[2001:db8:f00::1002]:23456" .parse::() .unwrap(); let v6_2 = "[2001:db8:f00::2001]:12345" .parse::() .unwrap(); let v6_3 = "[2001:db8:f00::2001]:23456" .parse::() .unwrap(); // equality assert_eq!(v4_1, v4_1); assert_eq!(v6_1, v6_1); assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); assert!(v4_1 != v4_2); assert!(v6_1 != v6_2); // compare different addresses assert!(v4_1 < v4_2); assert!(v6_1 < v6_2); assert!(v4_2 > v4_1); assert!(v6_2 > v6_1); // compare the same address with different ports assert!(v4_2 < v4_3); assert!(v6_2 < v6_3); assert!(v4_3 > v4_2); assert!(v6_3 > v6_2); // compare different addresses with the same port assert!(v4_1 < v4_3); assert!(v6_1 < v6_3); assert!(v4_3 > v4_1); assert!(v6_3 > v6_1); // compare with an inferred right-hand side assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); } no-std-net-0.6.0/src/addr.rs000064400000000000000000000631100072674642500137170ustar 00000000000000// Effectively all the code in this repo is copied with permission from Rust's std library. // They hold the copyright (http://rust-lang.org/COPYRIGHT) and whatever other rights, but this // crate is MIT licensed also, so it's all good. #[cfg(all(test, not(target_os = "emscripten")))] mod tests; use core::cmp::Ordering; use core::fmt::{self, Write}; use core::hash; use core::iter; use core::option; use core::slice; use super::helper::WriteHelper; use super::{IpAddr, Ipv4Addr, Ipv6Addr}; /// An internet socket address, either IPv4 or IPv6. /// /// Internet socket addresses consist of an [IP address], a 16-bit port number, as well /// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and /// [`SocketAddrV6`]'s respective documentation for more details. /// /// [IP address]: IpAddr /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// /// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); /// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.is_ipv4(), true); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum SocketAddr { /// An IPv4 socket address. V4(SocketAddrV4), /// An IPv6 socket address. V6(SocketAddrV6), } /// An IPv4 socket address. /// /// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as /// stated in [IETF RFC 793]. /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`IPv4` address]: Ipv4Addr /// /// # Examples /// /// ``` /// use no_std_net::{Ipv4Addr, SocketAddrV4}; /// /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// /// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); /// assert_eq!(socket.port(), 8080); /// ``` #[derive(Copy)] pub struct SocketAddrV4 { addr: Ipv4Addr, port: u16, } /// An IPv6 socket address. /// /// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well /// as fields containing the traffic class, the flow label, and a scope identifier /// (see [IETF RFC 2553, Section 3.3] for more details). /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [`IPv6` address]: Ipv6Addr /// /// # Examples /// /// ``` /// use no_std_net::{Ipv6Addr, SocketAddrV6}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// /// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); /// assert_eq!(socket.port(), 8080); /// ``` #[derive(Copy)] pub struct SocketAddrV6 { addr: Ipv6Addr, port: u16, flow_info: u32, scope_id: u32, } impl SocketAddr { /// Creates a new socket address from an [IP address] and a port number. /// /// [IP address]: IpAddr /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); /// assert_eq!(socket.port(), 8080); /// ``` pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { match ip { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), } } /// Returns the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); /// ``` pub const fn ip(&self) -> IpAddr { match *self { SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), } } /// Changes the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// ``` pub fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), } } /// Returns the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// assert_eq!(socket.port(), 8080); /// ``` pub const fn port(&self) -> u16 { match *self { SocketAddr::V4(ref a) => a.port(), SocketAddr::V6(ref a) => a.port(), } } /// Changes the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// socket.set_port(1025); /// assert_eq!(socket.port(), 1025); /// ``` pub fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), SocketAddr::V6(ref mut a) => a.set_port(new_port), } } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an /// [`IPv4` address], and [`false`] otherwise. /// /// [IP address]: IpAddr /// [`IPv4` address]: IpAddr::V4 /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); /// assert_eq!(socket.is_ipv4(), true); /// assert_eq!(socket.is_ipv6(), false); /// ``` pub const fn is_ipv4(&self) -> bool { matches!(*self, SocketAddr::V4(_)) } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an /// [`IPv6` address], and [`false`] otherwise. /// /// [IP address]: IpAddr /// [`IPv6` address]: IpAddr::V6 /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv6Addr, SocketAddr}; /// /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); /// assert_eq!(socket.is_ipv4(), false); /// assert_eq!(socket.is_ipv6(), true); /// ``` pub const fn is_ipv6(&self) -> bool { matches!(*self, SocketAddr::V6(_)) } } impl SocketAddrV4 { /// Creates a new socket address from an [`IPv4` address] and a port number. /// /// [`IPv4` address]: Ipv4Addr /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV4, Ipv4Addr}; /// /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// ``` pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { addr: ip, port: port, } } /// Returns the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV4, Ipv4Addr}; /// /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); /// ``` pub const fn ip(&self) -> &Ipv4Addr { &self.addr } /// Changes the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV4, Ipv4Addr}; /// /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); /// ``` pub fn set_ip(&mut self, new_ip: Ipv4Addr) { self.addr = new_ip } /// Returns the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV4, Ipv4Addr}; /// /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// assert_eq!(socket.port(), 8080); /// ``` pub const fn port(&self) -> u16 { self.port } /// Changes the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV4, Ipv4Addr}; /// /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` pub fn set_port(&mut self, new_port: u16) { self.port = new_port; } } impl SocketAddrV6 { /// Creates a new socket address from an [`IPv6` address], a 16-bit port number, /// and the `flowinfo` and `scope_id` fields. /// /// For more information on the meaning and layout of the `flowinfo` and `scope_id` /// parameters, see [IETF RFC 2553, Section 3.3]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [`IPv6` address]: Ipv6Addr /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// ``` pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { SocketAddrV6 { addr: ip, port: port, flow_info: flowinfo, scope_id: scope_id, } } /// Returns the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// ``` pub const fn ip(&self) -> &Ipv6Addr { &self.addr } /// Changes the IP address associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// ``` pub fn set_ip(&mut self, new_ip: Ipv6Addr) { self.addr = new_ip } /// Returns the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// assert_eq!(socket.port(), 8080); /// ``` pub const fn port(&self) -> u16 { self.port } /// Changes the port number associated with this socket address. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` pub fn set_port(&mut self, new_port: u16) { self.port = new_port } /// Returns the flow information associated with this address. /// /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, /// as specified in [IETF RFC 2553, Section 3.3]. /// It combines information about the flow label and the traffic class as specified /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); /// assert_eq!(socket.flowinfo(), 10); /// ``` pub const fn flowinfo(&self) -> u32 { self.flow_info } /// Changes the flow information associated with this socket address. /// /// See [`SocketAddrV6::flowinfo`]'s documentation for more details. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); /// socket.set_flowinfo(56); /// assert_eq!(socket.flowinfo(), 56); /// ``` pub fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flow_info = new_flowinfo; } /// Returns the scope ID associated with this address. /// /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, /// as specified in [IETF RFC 2553, Section 3.3]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); /// assert_eq!(socket.scope_id(), 78); /// ``` pub const fn scope_id(&self) -> u32 { self.scope_id } /// Changes the scope ID associated with this socket address. /// /// See [`SocketAddrV6::scope_id`]'s documentation for more details. /// /// # Examples /// /// ``` /// use no_std_net::{SocketAddrV6, Ipv6Addr}; /// /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); /// socket.set_scope_id(42); /// assert_eq!(socket.scope_id(), 42); /// ``` pub fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } } impl From for SocketAddr { /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. fn from(sock4: SocketAddrV4) -> SocketAddr { SocketAddr::V4(sock4) } } impl From for SocketAddr { /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. fn from(sock6: SocketAddrV6) -> SocketAddr { SocketAddr::V6(sock6) } } impl> From<(I, u16)> for SocketAddr { /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. /// /// This conversion creates a [`SocketAddr::V4`] for a [`IpAddr::V4`] /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`]. /// /// `u16` is treated as port of the newly created [`SocketAddr`]. fn from(pieces: (I, u16)) -> SocketAddr { SocketAddr::new(pieces.0.into(), pieces.1) } } impl fmt::Display for SocketAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { SocketAddr::V4(ref a) => a.fmt(f), SocketAddr::V6(ref a) => a.fmt(f), } } } impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl fmt::Display for SocketAddrV4 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Fast path: if there's no alignment stuff, write to the output buffer // directly if f.precision().is_none() && f.width().is_none() { write!(f, "{}:{}", self.ip(), self.port()) } else { const IPV4_SOCKET_BUF_LEN: usize = (3 * 4) // the segments + 3 // the separators + 1 + 5; // the port let mut buf = [0; IPV4_SOCKET_BUF_LEN]; let mut buf_slice = WriteHelper::new(&mut buf[..]); // Unwrap is fine because writing to a sufficiently-sized // buffer is infallible write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); let len = IPV4_SOCKET_BUF_LEN - buf_slice.into_raw().len(); // This unsafe is OK because we know what is being written to the buffer let buf = unsafe { core::str::from_utf8_unchecked(&buf[..len]) }; f.pad(buf) } } } impl fmt::Debug for SocketAddrV4 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl fmt::Display for SocketAddrV6 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Fast path: if there's no alignment stuff, write to the output // buffer directly if f.precision().is_none() && f.width().is_none() { match self.scope_id() { 0 => write!(f, "[{}]:{}", self.ip(), self.port()), scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()), } } else { const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address + 7 // The colon separators + 2 // The brackets + 1 + 10 // The scope id + 1 + 5; // The port let mut buf = [0; IPV6_SOCKET_BUF_LEN]; let mut buf_slice = WriteHelper::new(&mut buf[..]); match self.scope_id() { 0 => write!(buf_slice, "[{}]:{}", self.ip(), self.port()), scope_id => write!(buf_slice, "[{}%{}]:{}", self.ip(), scope_id, self.port()), } // Unwrap is fine because writing to a sufficiently-sized // buffer is infallible .unwrap(); let len = IPV6_SOCKET_BUF_LEN - buf_slice.into_raw().len(); // This unsafe is OK because we know what is being written to the buffer let buf = unsafe { core::str::from_utf8_unchecked(&buf[..len]) }; f.pad(buf) } } } impl fmt::Debug for SocketAddrV6 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl Clone for SocketAddrV4 { fn clone(&self) -> SocketAddrV4 { *self } } impl Clone for SocketAddrV6 { fn clone(&self) -> SocketAddrV6 { *self } } impl PartialEq for SocketAddrV4 { fn eq(&self, other: &SocketAddrV4) -> bool { self.port == other.port && self.addr == other.addr } } impl PartialEq for SocketAddrV6 { fn eq(&self, other: &SocketAddrV6) -> bool { self.port == other.port && self.addr == other.addr && self.flow_info == other.flow_info && self.scope_id == other.scope_id } } impl Eq for SocketAddrV4 {} impl Eq for SocketAddrV6 {} impl PartialOrd for SocketAddrV4 { fn partial_cmp(&self, other: &SocketAddrV4) -> Option { Some(self.cmp(other)) } } impl PartialOrd for SocketAddrV6 { fn partial_cmp(&self, other: &SocketAddrV6) -> Option { Some(self.cmp(other)) } } impl Ord for SocketAddrV4 { fn cmp(&self, other: &SocketAddrV4) -> Ordering { self.ip() .cmp(other.ip()) .then(self.port().cmp(&other.port())) } } impl Ord for SocketAddrV6 { fn cmp(&self, other: &SocketAddrV6) -> Ordering { self.ip() .cmp(other.ip()) .then(self.port().cmp(&other.port())) } } impl hash::Hash for SocketAddrV4 { fn hash(&self, s: &mut H) { (self.port, self.addr).hash(s) } } impl hash::Hash for SocketAddrV6 { fn hash(&self, s: &mut H) { (self.port, self.addr, self.flow_info, self.scope_id).hash(s) } } /// A trait for objects which can be converted or resolved to one or more /// [`SocketAddr`] values. /// /// This trait is used for generic address resolution when constructing network /// objects. By default it is implemented for the following types: /// /// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// /// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, /// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// /// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. [`u16`] is the port number. /// /// * [`&str`]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `:` pair where `` is a [`u16`] value. /// /// This trait allows constructing network objects like [`TcpStream`] or /// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than /// the other: for simple uses a string like `"localhost:12345"` is much nicer /// than manual construction of the corresponding [`SocketAddr`], but sometimes /// [`SocketAddr`] value is *the* main source of the address, and converting it to /// some other type (e.g., a string) just for it to be converted back to /// [`SocketAddr`] in constructor methods is pointless. /// /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// /// [`FromStr`]: core::str::FromStr /// [`&str`]: str #[cfg_attr(feature = "std", doc = "[`TcpStream`]: std::net::TcpStream")] #[cfg_attr( not(feature = "std"), doc = "[`TcpStream`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html" )] /// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs #[cfg_attr(feature = "std", doc = "[`UdpSocket`]: std::net::UdpSocket")] #[cfg_attr( not(feature = "std"), doc = "[`UdpSocket`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html" )] /// /// # Examples /// /// Creating a [`SocketAddr`] iterator that yields one item: /// /// ``` /// use no_std_net::{ToSocketAddrs, SocketAddr}; /// /// let addr = SocketAddr::from(([127, 0, 0, 1], 443)); /// let mut addrs_iter = addr.to_socket_addrs().unwrap(); /// /// assert_eq!(Some(addr), addrs_iter.next()); /// assert!(addrs_iter.next().is_none()); /// ``` /// /// Creating a [`SocketAddr`] iterator that yields multiple items: /// /// ``` /// use no_std_net::{SocketAddr, ToSocketAddrs}; /// /// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80)); /// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443)); /// let addrs = vec![addr1, addr2]; /// /// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap(); /// /// assert_eq!(Some(addr1), addrs_iter.next()); /// assert_eq!(Some(addr2), addrs_iter.next()); /// assert!(addrs_iter.next().is_none()); /// ``` pub trait ToSocketAddrs { /// Returned iterator over socket addresses which this type may correspond /// to. type Iter: Iterator; /// Converts this object to an iterator of resolved `SocketAddr`s. /// /// The returned iterator may not actually yield any values depending on the /// outcome of any resolution performed. /// /// Note that this function may block the current thread while resolution is /// performed. fn to_socket_addrs(&self) -> Result; } /// This is a placeholder for the core::result::Result type parameter, it is unused. #[derive(Debug)] pub enum ToSocketAddrError {} impl ToSocketAddrs for SocketAddr { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { Ok(Some(*self).into_iter()) } } impl ToSocketAddrs for SocketAddrV4 { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { SocketAddr::V4(*self).to_socket_addrs() } } impl ToSocketAddrs for SocketAddrV6 { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { SocketAddr::V6(*self).to_socket_addrs() } } impl ToSocketAddrs for (IpAddr, u16) { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { let (ip, port) = *self; match ip { IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), } } } impl ToSocketAddrs for (Ipv4Addr, u16) { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { let (ip, port) = *self; SocketAddrV4::new(ip, port).to_socket_addrs() } } impl ToSocketAddrs for (Ipv6Addr, u16) { type Iter = option::IntoIter; fn to_socket_addrs(&self) -> Result, ToSocketAddrError> { let (ip, port) = *self; SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs() } } impl<'a> ToSocketAddrs for &'a [SocketAddr] { type Iter = iter::Cloned>; fn to_socket_addrs(&self) -> Result { Ok(self.iter().cloned()) } } impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { type Iter = T::Iter; fn to_socket_addrs(&self) -> Result { (**self).to_socket_addrs() } } no-std-net-0.6.0/src/de.rs000064400000000000000000000207100072674642500133740ustar 00000000000000use addr::{SocketAddr, SocketAddrV4, SocketAddrV6}; use core::{fmt, str}; use ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use serde::de::{Deserialize, Deserializer, EnumAccess, Error, Unexpected, VariantAccess, Visitor}; macro_rules! variant_identifier { ( $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) $expecting_message: expr, $variants_name: ident ) => { enum $name_kind { $( $variant ),* } static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*]; impl<'de> Deserialize<'de> for $name_kind { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct KindVisitor; impl<'de> Visitor<'de> for KindVisitor { type Value = $name_kind; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str($expecting_message) } fn visit_u32(self, value: u32) -> Result where E: Error, { match value { $( $index => Ok($name_kind :: $variant), )* _ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),), } } fn visit_str(self, value: &str) -> Result where E: Error, { match value { $( stringify!($variant) => Ok($name_kind :: $variant), )* _ => Err(Error::unknown_variant(value, $variants_name)), } } fn visit_bytes(self, value: &[u8]) -> Result where E: Error, { match value { $( $bytes => Ok($name_kind :: $variant), )* _ => { match str::from_utf8(value) { Ok(value) => Err(Error::unknown_variant(value, $variants_name)), Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)), } } } } } deserializer.deserialize_identifier(KindVisitor) } } } } macro_rules! deserialize_enum { ( $name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) $expecting_message: expr, $deserializer: expr ) => { variant_identifier!{ $name_kind ( $($variant; $bytes; $index),* ) $expecting_message, VARIANTS } struct EnumVisitor; impl<'de> Visitor<'de> for EnumVisitor { type Value = $name; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(concat!("a ", stringify!($name))) } fn visit_enum(self, data: A) -> Result where A: EnumAccess<'de>, { match data.variant()? { $( ($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant), )* } } } $deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor) } } macro_rules! parse_ip_impl { ($expecting:tt $ty:ty; $size:tt) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { struct IpAddrVisitor; impl<'de> Visitor<'de> for IpAddrVisitor { type Value = $ty; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str($expecting) } fn visit_str(self, s: &str) -> Result where E: Error, { s.parse().map_err(Error::custom) } } deserializer.deserialize_str(IpAddrVisitor) } else { <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) } } } }; } impl<'de> Deserialize<'de> for IpAddr { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { struct IpAddrVisitor; impl<'de> Visitor<'de> for IpAddrVisitor { type Value = IpAddr; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("IP address") } fn visit_str(self, s: &str) -> Result where E: Error, { s.parse().map_err(Error::custom) } } deserializer.deserialize_str(IpAddrVisitor) } else { deserialize_enum! { IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) "`V4` or `V6`", deserializer } } } } parse_ip_impl!("IPv4 address" Ipv4Addr; 4); parse_ip_impl!("IPv6 address" Ipv6Addr; 16); macro_rules! parse_socket_impl { ($expecting:tt $ty:ty, $new:expr) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { struct SocketAddrVisitor; impl<'de> Visitor<'de> for SocketAddrVisitor { type Value = $ty; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str($expecting) } fn visit_str(self, s: &str) -> Result where E: Error, { s.parse().map_err(Error::custom) } } deserializer.deserialize_str(SocketAddrVisitor) } else { <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port)) } } } }; } impl<'de> Deserialize<'de> for SocketAddr { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { struct SocketAddrVisitor; impl<'de> Visitor<'de> for SocketAddrVisitor { type Value = SocketAddr; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("socket address") } fn visit_str(self, s: &str) -> Result where E: Error, { s.parse().map_err(Error::custom) } } deserializer.deserialize_str(SocketAddrVisitor) } else { deserialize_enum! { SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) "`V4` or `V6`", deserializer } } } } parse_socket_impl!("IPv4 socket address" SocketAddrV4, SocketAddrV4::new); parse_socket_impl!("IPv6 socket address" SocketAddrV6, |ip, port| SocketAddrV6::new( ip, port, 0, 0 )); // Note: `::ser::tests` tests both serializing and deserializing tokens no-std-net-0.6.0/src/helper.rs000064400000000000000000000014160072674642500142650ustar 00000000000000use core::cmp; use core::fmt::{self, Write}; use core::mem; /// A partial reimplementation of `impl std::io::Write for &mut [u8]`. /// /// There are probably simpler ways to do this, this was the first thing that /// came to mind. pub(crate) struct WriteHelper<'a>(&'a mut [u8]); impl<'a> WriteHelper<'a> { pub(crate) fn new(inner: &'a mut [u8]) -> Self { Self(inner) } pub(crate) fn into_raw(self) -> &'a mut [u8] { self.0 } } impl<'a> Write for WriteHelper<'a> { fn write_str(&mut self, data: &str) -> fmt::Result { let amt = cmp::min(data.len(), self.0.len()); let (a, b) = mem::replace(&mut self.0, &mut []).split_at_mut(amt); a.copy_from_slice(&data[..amt].as_bytes()); self.0 = b; Ok(()) } } no-std-net-0.6.0/src/ip/tests.rs000064400000000000000000001001200072674642500145500ustar 00000000000000// A lot of things are behind cfg(feature = "unstable_ip") #![allow(unused_variables)] use alloc::string::ToString; use core::str::FromStr; use crate::test::{sa4, sa6, tsa}; use crate::*; #[test] fn test_from_str_ipv4() { assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); assert_eq!( Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse() ); assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); // out of range let none: Option = "256.0.0.1".parse().ok(); assert_eq!(None, none); // too short let none: Option = "255.0.0".parse().ok(); assert_eq!(None, none); // too long let none: Option = "255.0.0.1.2".parse().ok(); assert_eq!(None, none); // no number between dots let none: Option = "255.0..1".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_ipv6() { assert_eq!( Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse() ); assert_eq!( Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse() ); assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); assert_eq!( Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse() ); // too long group let none: Option = "::00000".parse().ok(); assert_eq!(None, none); // too short let none: Option = "1:2:3:4:5:6:7".parse().ok(); assert_eq!(None, none); // too long let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); assert_eq!(None, none); // triple colon let none: Option = "1:2:::6:7:8".parse().ok(); assert_eq!(None, none); // two double colons let none: Option = "1:2::6::8".parse().ok(); assert_eq!(None, none); // `::` indicating zero groups of zeros let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_ipv4_in_ipv6() { assert_eq!( Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse() ); assert_eq!( Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse() ); assert_eq!( Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), "64:ff9b::192.0.2.33".parse() ); assert_eq!( Ok(Ipv6Addr::new( 0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545 )), "2001:db8:122:c000:2:2100:192.0.2.33".parse() ); // colon after v4 let none: Option = "::127.0.0.1:".parse().ok(); assert_eq!(None, none); // not enough groups let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); assert_eq!(None, none); // too many groups let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_socket_addr() { assert_eq!( Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse() ); assert_eq!( Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse() ); assert_eq!( Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), "[2a02:6b8:0:1::1]:53".parse() ); assert_eq!( Ok(SocketAddrV6::new( Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0 )), "[2a02:6b8:0:1::1]:53".parse() ); assert_eq!( Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse() ); assert_eq!( Ok(SocketAddrV6::new( Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0 )), "[::127.0.0.1]:22".parse() ); // without port let none: Option = "127.0.0.1".parse().ok(); assert_eq!(None, none); // without port let none: Option = "127.0.0.1:".parse().ok(); assert_eq!(None, none); // wrong brackets around v4 let none: Option = "[127.0.0.1]:22".parse().ok(); assert_eq!(None, none); // port out of range let none: Option = "127.0.0.1:123456".parse().ok(); assert_eq!(None, none); } #[test] fn ipv4_addr_to_string() { assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); // Short address assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); // Long address assert_eq!( Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127" ); // Test padding assert_eq!( &format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 " ); assert_eq!( &format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1" ); } #[test] fn ipv6_addr_to_string() { // ipv4-mapped address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); // ipv4-compatible address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); assert_eq!(a1.to_string(), "::192.0.2.128"); // v6 address with no zero segments assert_eq!( Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f" ); // longest possible IPv6 length assert_eq!( Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), "1111:2222:3333:4444:5555:6666:7777:8888" ); // padding assert_eq!( &format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 " ); assert_eq!( &format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8" ); // reduce a single run of zeros assert_eq!( "ae::ffff:102:304", Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() ); // don't reduce just a single zero segment assert_eq!( "1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string() ); // 'any' address assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); // loopback address assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); // ends in zeros assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); // two runs of zeros, second one is longer assert_eq!( "1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string() ); // two runs of zeros, equal length assert_eq!( "1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string() ); // don't prefix `0x` to each segment in `dbg!`. assert_eq!( "1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)) ); } #[test] fn ipv4_to_ipv6() { assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() ); assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() ); } #[cfg(feature = "unstable_ip")] #[test] fn ipv6_to_ipv4_mapped() { assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None ); } #[test] fn ipv6_to_ipv4() { assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); assert_eq!( Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); assert_eq!( Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None ); } #[test] fn ip_properties() { macro_rules! ip { ($s:expr) => { IpAddr::from_str($s).unwrap() }; } macro_rules! check { ($s:expr) => { check!($s, 0); }; ($s:expr, $mask:expr) => {{ let unspec: u8 = 1 << 0; let loopback: u8 = 1 << 1; let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; if ($mask & unspec) == unspec { assert!(ip!($s).is_unspecified()); } else { assert!(!ip!($s).is_unspecified()); } if ($mask & loopback) == loopback { assert!(ip!($s).is_loopback()); } else { assert!(!ip!($s).is_loopback()); } #[cfg(feature = "unstable_ip")] { if ($mask & global) == global { assert!(ip!($s).is_global()); } else { assert!(!ip!($s).is_global()); } } if ($mask & multicast) == multicast { assert!(ip!($s).is_multicast()); } else { assert!(!ip!($s).is_multicast()); } #[cfg(feature = "unstable_ip")] { if ($mask & doc) == doc { assert!(ip!($s).is_documentation()); } else { assert!(!ip!($s).is_documentation()); } } }}; } let unspec: u8 = 1 << 0; let loopback: u8 = 1 << 1; let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; check!("0.0.0.0", unspec); check!("0.0.0.1"); check!("0.1.0.0"); check!("10.9.8.7"); check!("127.1.2.3", loopback); check!("172.31.254.253"); check!("169.254.253.242"); check!("192.0.2.183", doc); check!("192.1.2.183", global); check!("192.168.254.253"); check!("198.51.100.0", doc); check!("203.0.113.0", doc); check!("203.2.113.0", global); check!("224.0.0.0", global | multicast); check!("239.255.255.255", global | multicast); check!("255.255.255.255"); // make sure benchmarking addresses are not global check!("198.18.0.0"); check!("198.18.54.2"); check!("198.19.255.255"); // make sure addresses reserved for protocol assignment are not global check!("192.0.0.0"); check!("192.0.0.255"); check!("192.0.0.100"); // make sure reserved addresses are not global check!("240.0.0.0"); check!("251.54.1.76"); check!("254.255.255.255"); // make sure shared addresses are not global check!("100.64.0.0"); check!("100.127.255.255"); check!("100.100.100.0"); check!("::", unspec); check!("::1", loopback); check!("::0.0.0.2", global); check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); check!("fe80:ffff::"); check!("febf:ffff::"); check!("fec0::", global); check!("ff01::", multicast); check!("ff02::", multicast); check!("ff03::", multicast); check!("ff04::", multicast); check!("ff05::", multicast); check!("ff08::", multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); check!("102:304:506:708:90a:b0c:d0e:f10", global); } #[test] fn ipv4_properties() { macro_rules! ip { ($s:expr) => { Ipv4Addr::from_str($s).unwrap() }; } macro_rules! check { ($s:expr) => { check!($s, 0); }; ($s:expr, $mask:expr) => {{ let unspec: u16 = 1 << 0; let loopback: u16 = 1 << 1; let private: u16 = 1 << 2; let link_local: u16 = 1 << 3; let global: u16 = 1 << 4; let multicast: u16 = 1 << 5; let broadcast: u16 = 1 << 6; let documentation: u16 = 1 << 7; let benchmarking: u16 = 1 << 8; let ietf_protocol_assignment: u16 = 1 << 9; let reserved: u16 = 1 << 10; let shared: u16 = 1 << 11; if ($mask & unspec) == unspec { assert!(ip!($s).is_unspecified()); } else { assert!(!ip!($s).is_unspecified()); } if ($mask & loopback) == loopback { assert!(ip!($s).is_loopback()); } else { assert!(!ip!($s).is_loopback()); } if ($mask & private) == private { assert!(ip!($s).is_private()); } else { assert!(!ip!($s).is_private()); } if ($mask & link_local) == link_local { assert!(ip!($s).is_link_local()); } else { assert!(!ip!($s).is_link_local()); } #[cfg(feature = "unstable_ip")] { if ($mask & global) == global { assert!(ip!($s).is_global()); } else { assert!(!ip!($s).is_global()); } } if ($mask & multicast) == multicast { assert!(ip!($s).is_multicast()); } else { assert!(!ip!($s).is_multicast()); } if ($mask & broadcast) == broadcast { assert!(ip!($s).is_broadcast()); } else { assert!(!ip!($s).is_broadcast()); } if ($mask & documentation) == documentation { assert!(ip!($s).is_documentation()); } else { assert!(!ip!($s).is_documentation()); } #[cfg(feature = "unstable_ip")] { if ($mask & benchmarking) == benchmarking { assert!(ip!($s).is_benchmarking()); } else { assert!(!ip!($s).is_benchmarking()); } if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { assert!(ip!($s).is_ietf_protocol_assignment()); } else { assert!(!ip!($s).is_ietf_protocol_assignment()); } if ($mask & reserved) == reserved { assert!(ip!($s).is_reserved()); } else { assert!(!ip!($s).is_reserved()); } if ($mask & shared) == shared { assert!(ip!($s).is_shared()); } else { assert!(!ip!($s).is_shared()); } } }}; } let unspec: u16 = 1 << 0; let loopback: u16 = 1 << 1; let private: u16 = 1 << 2; let link_local: u16 = 1 << 3; let global: u16 = 1 << 4; let multicast: u16 = 1 << 5; let broadcast: u16 = 1 << 6; let documentation: u16 = 1 << 7; let benchmarking: u16 = 1 << 8; let ietf_protocol_assignment: u16 = 1 << 9; let reserved: u16 = 1 << 10; let shared: u16 = 1 << 11; check!("0.0.0.0", unspec); check!("0.0.0.1"); check!("0.1.0.0"); check!("10.9.8.7", private); check!("127.1.2.3", loopback); check!("172.31.254.253", private); check!("169.254.253.242", link_local); check!("192.0.2.183", documentation); check!("192.1.2.183", global); check!("192.168.254.253", private); check!("198.51.100.0", documentation); check!("203.0.113.0", documentation); check!("203.2.113.0", global); check!("224.0.0.0", global | multicast); check!("239.255.255.255", global | multicast); check!("255.255.255.255", broadcast); check!("198.18.0.0", benchmarking); check!("198.18.54.2", benchmarking); check!("198.19.255.255", benchmarking); check!("192.0.0.0", ietf_protocol_assignment); check!("192.0.0.255", ietf_protocol_assignment); check!("192.0.0.100", ietf_protocol_assignment); check!("240.0.0.0", reserved); check!("251.54.1.76", reserved); check!("254.255.255.255", reserved); check!("100.64.0.0", shared); check!("100.127.255.255", shared); check!("100.100.100.0", shared); } #[test] fn ipv6_properties() { macro_rules! ip { ($s:expr) => { Ipv6Addr::from_str($s).unwrap() }; } macro_rules! check { ($s:expr, &[$($octet:expr),*], $mask:expr) => { assert_eq!($s, ip!($s).to_string()); let octets = &[$($octet),*]; assert_eq!(&ip!($s).octets(), octets); assert_eq!(Ipv6Addr::from(*octets), ip!($s)); let unspecified: u16 = 1 << 0; let loopback: u16 = 1 << 1; let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; let multicast_interface_local: u16 = 1 << 9; let multicast_link_local: u16 = 1 << 10; let multicast_realm_local: u16 = 1 << 11; let multicast_admin_local: u16 = 1 << 12; let multicast_site_local: u16 = 1 << 13; let multicast_organization_local: u16 = 1 << 14; let multicast_global: u16 = 1 << 15; let multicast: u16 = multicast_interface_local | multicast_admin_local | multicast_global | multicast_link_local | multicast_realm_local | multicast_site_local | multicast_organization_local; if ($mask & unspecified) == unspecified { assert!(ip!($s).is_unspecified()); } else { assert!(!ip!($s).is_unspecified()); } if ($mask & loopback) == loopback { assert!(ip!($s).is_loopback()); } else { assert!(!ip!($s).is_loopback()); } #[cfg(feature = "unstable_ip")] { if ($mask & unique_local) == unique_local { assert!(ip!($s).is_unique_local()); } else { assert!(!ip!($s).is_unique_local()); } if ($mask & global) == global { assert!(ip!($s).is_global()); } else { assert!(!ip!($s).is_global()); } if ($mask & unicast_link_local) == unicast_link_local { assert!(ip!($s).is_unicast_link_local()); } else { assert!(!ip!($s).is_unicast_link_local()); } if ($mask & unicast_site_local) == unicast_site_local { assert!(ip!($s).is_unicast_site_local()); } else { assert!(!ip!($s).is_unicast_site_local()); } if ($mask & unicast_global) == unicast_global { assert!(ip!($s).is_unicast_global()); } else { assert!(!ip!($s).is_unicast_global()); } if ($mask & documentation) == documentation { assert!(ip!($s).is_documentation()); } else { assert!(!ip!($s).is_documentation()); } if ($mask & multicast) != 0 { assert!(ip!($s).multicast_scope().is_some()); assert!(ip!($s).is_multicast()); } else { assert!(ip!($s).multicast_scope().is_none()); assert!(!ip!($s).is_multicast()); } if ($mask & multicast_interface_local) == multicast_interface_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::InterfaceLocal); } if ($mask & multicast_link_local) == multicast_link_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::LinkLocal); } if ($mask & multicast_realm_local) == multicast_realm_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::RealmLocal); } if ($mask & multicast_admin_local) == multicast_admin_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::AdminLocal); } if ($mask & multicast_site_local) == multicast_site_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::SiteLocal); } if ($mask & multicast_organization_local) == multicast_organization_local { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::OrganizationLocal); } if ($mask & multicast_global) == multicast_global { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::Global); } } } } let unspecified: u16 = 1 << 0; let loopback: u16 = 1 << 1; let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; let multicast_interface_local: u16 = 1 << 9; let multicast_link_local: u16 = 1 << 10; let multicast_realm_local: u16 = 1 << 11; let multicast_admin_local: u16 = 1 << 12; let multicast_site_local: u16 = 1 << 13; let multicast_organization_local: u16 = 1 << 14; let multicast_global: u16 = 1 << 15; check!( "::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified ); check!( "::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback ); check!( "::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global ); check!( "1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global ); check!( "fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local ); check!( "fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local ); check!( "fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local ); check!( "fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local ); check!( "febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local ); check!( "febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local ); check!( "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &[ 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], unicast_link_local ); check!( "fe80::ffff:ffff:ffff:ffff", &[ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], unicast_link_local ); check!( "fe80:0:0:1::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local ); check!( "fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_site_local | unicast_global | global ); check!( "ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_interface_local ); check!( "ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local ); check!( "ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local ); check!( "ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local ); check!( "ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local ); check!( "ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_organization_local ); check!( "ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_global | global ); check!( "2001:db8:85a3::8a2e:370:7334", &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], documentation ); check!( "102:304:506:708:90a:b0c:d0e:f10", &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], global | unicast_global ); } #[test] fn to_socket_addr_socketaddr() { let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); assert_eq!(Ok(vec![a]), tsa(a)); } #[test] fn test_ipv4_to_int() { let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); assert_eq!(u32::from(a), 0x11223344); } #[test] fn test_int_to_ipv4() { let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); assert_eq!(Ipv4Addr::from(0x11223344), a); } #[test] fn test_ipv6_to_int() { let a = Ipv6Addr::new( 0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11, ); assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); } #[test] fn test_int_to_ipv6() { let a = Ipv6Addr::new( 0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11, ); assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); } #[test] fn ipv4_from_constructors() { assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); assert!(Ipv4Addr::LOCALHOST.is_loopback()); assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); assert!(Ipv4Addr::BROADCAST.is_broadcast()); } #[test] fn ipv6_from_contructors() { assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); assert!(Ipv6Addr::LOCALHOST.is_loopback()); assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); } #[test] fn ipv4_from_octets() { assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) } #[test] fn ipv6_from_segments() { let from_u16s = Ipv6Addr::from([ 0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff, ]); let new = Ipv6Addr::new( 0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff, ); assert_eq!(new, from_u16s); } #[test] fn ipv6_from_octets() { let from_u16s = Ipv6Addr::from([ 0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff, ]); let from_u8s = Ipv6Addr::from([ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]); assert_eq!(from_u16s, from_u8s); } #[test] fn cmp() { let v41 = Ipv4Addr::new(100, 64, 3, 3); let v42 = Ipv4Addr::new(192, 0, 2, 2); let v61 = "2001:db8:f00::1002".parse::().unwrap(); let v62 = "2001:db8:f00::2001".parse::().unwrap(); assert!(v41 < v42); assert!(v61 < v62); assert_eq!(v41, IpAddr::V4(v41)); assert_eq!(v61, IpAddr::V6(v61)); assert!(v41 != IpAddr::V4(v42)); assert!(v61 != IpAddr::V6(v62)); assert!(v41 < IpAddr::V4(v42)); assert!(v61 < IpAddr::V6(v62)); assert!(IpAddr::V4(v41) < v42); assert!(IpAddr::V6(v61) < v62); assert!(v41 < IpAddr::V6(v61)); assert!(IpAddr::V4(v41) < v61); } #[test] fn is_v4() { let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); assert!(ip.is_ipv4()); assert!(!ip.is_ipv6()); } #[test] fn is_v6() { let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); assert!(!ip.is_ipv4()); assert!(ip.is_ipv6()); } #[test] fn ipv4_const() { // test that the methods of `Ipv4Addr` are usable in a const context const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); const OCTETS: [u8; 4] = IP_ADDRESS.octets(); assert_eq!(OCTETS, [127, 0, 0, 1]); const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); assert!(!IS_UNSPECIFIED); const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); assert!(IS_LOOPBACK); const IS_PRIVATE: bool = IP_ADDRESS.is_private(); assert!(!IS_PRIVATE); const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); assert!(!IS_LINK_LOCAL); #[cfg(feature = "unstable_ip")] { const IS_GLOBAL: bool = IP_ADDRESS.is_global(); assert!(!IS_GLOBAL); const IS_SHARED: bool = IP_ADDRESS.is_shared(); assert!(!IS_SHARED); const IS_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment(); assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); assert!(!IS_BENCHMARKING); const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); assert!(!IS_RESERVED); } const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); assert!(!IS_BROADCAST); const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); assert!(!IS_DOCUMENTATION); const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); assert_eq!( IP_V6_COMPATIBLE, Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) ); const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); assert_eq!( IP_V6_MAPPED, Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) ); } #[test] fn ipv6_const() { // test that the methods of `Ipv6Addr` are usable in a const context const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); const OCTETS: [u8; 16] = IP_ADDRESS.octets(); assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); assert!(!IS_UNSPECIFIED); const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); assert!(IS_LOOPBACK); #[cfg(feature = "unstable_ip")] { const IS_GLOBAL: bool = IP_ADDRESS.is_global(); assert!(!IS_GLOBAL); const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); assert!(!IS_UNIQUE_LOCAL); const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); assert!(!IS_UNICAST_LINK_LOCAL); const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local(); assert!(!IS_UNICAST_SITE_LOCAL); const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); assert!(!IS_DOCUMENTATION); const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); assert!(!IS_UNICAST_GLOBAL); const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); assert_eq!(MULTICAST_SCOPE, None); } const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); } #[test] fn ip_const() { // test that the methods of `IpAddr` are usable in a const context const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); assert!(!IS_UNSPECIFIED); const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); assert!(IS_LOOPBACK); #[cfg(feature = "unstable_ip")] { const IS_GLOBAL: bool = IP_ADDRESS.is_global(); assert!(!IS_GLOBAL); } const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); assert!(IS_IP_V4); const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); assert!(!IS_IP_V6); } no-std-net-0.6.0/src/ip.rs000064400000000000000000001625450072674642500134310ustar 00000000000000// Effectively all the code in this repo is copied with permission from Rust's std library. // They hold the copyright (http://rust-lang.org/COPYRIGHT) and whatever other rights, but this // crate is MIT licensed also, so it's all good. // Tests for this module #[cfg(all(test, not(target_os = "emscripten")))] mod tests; use core::cmp::Ordering; use core::fmt::{self, Write}; use core::hash; use super::helper::WriteHelper; /// An IP address, either IPv4 or IPv6. /// /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// /// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); /// assert_eq!("::1".parse(), Ok(localhost_v6)); /// /// assert_eq!(localhost_v4.is_ipv6(), false); /// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum IpAddr { /// An IPv4 address. V4(Ipv4Addr), /// An IPv6 address. V6(Ipv6Addr), } /// An IPv4 address. /// /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. /// They are usually represented as four octets. /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 /// /// # Textual representation /// /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal /// notation, divided by `.` (this is called "dot-decimal notation"). /// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943]. /// /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 /// [`FromStr`]: core::str::FromStr /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let localhost = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// ``` #[derive(Copy)] pub struct Ipv4Addr { // Octets stored in transmit order. inner: [u8; 4], } /// An IPv6 address. /// /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. /// They are usually represented as eight 16-bit segments. /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Textual representation /// /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent /// an IPv6 address in text, but in general, each segments is written in hexadecimal /// notation, and segments are separated by `:`. For more information, see /// [IETF RFC 5952]. /// /// [`FromStr`]: core::str::FromStr /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); /// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// ``` #[derive(Copy)] pub struct Ipv6Addr { // Octets stored in transmit order. inner: [u8; 16], } #[allow(missing_docs)] #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] #[cfg(feature = "unstable_ip")] pub enum Ipv6MulticastScope { InterfaceLocal, LinkLocal, RealmLocal, AdminLocal, SiteLocal, OrganizationLocal, Global, } impl IpAddr { /// Returns [`true`] for the special 'unspecified' address. /// /// See the documentation for [`Ipv4Addr::is_unspecified()`] and /// [`Ipv6Addr::is_unspecified()`] for more details. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` #[inline] pub const fn is_unspecified(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_unspecified(), IpAddr::V6(ip) => ip.is_unspecified(), } } /// Returns [`true`] if this is a loopback address. /// /// See the documentation for [`Ipv4Addr::is_loopback()`] and /// [`Ipv6Addr::is_loopback()`] for more details. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` #[inline] pub const fn is_loopback(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_loopback(), IpAddr::V6(ip) => ip.is_loopback(), } } /// Returns [`true`] if the address appears to be globally routable. /// /// See the documentation for [`Ipv4Addr::is_global()`] and /// [`Ipv6Addr::is_global()`] for more details. /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), } } /// Returns [`true`] if this is a multicast address. /// /// See the documentation for [`Ipv4Addr::is_multicast()`] and /// [`Ipv6Addr::is_multicast()`] for more details. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` #[inline] pub const fn is_multicast(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_multicast(), IpAddr::V6(ip) => ip.is_multicast(), } } /// Returns [`true`] if this address is in a range designated for documentation. /// /// See the documentation for [`Ipv4Addr::is_documentation()`] and /// [`Ipv6Addr::is_documentation()`] for more details. /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); /// assert_eq!( /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), /// true /// ); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), } } /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] /// otherwise. /// /// [`IPv4` address]: IpAddr::V4 /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); /// ``` #[inline] pub const fn is_ipv4(&self) -> bool { matches!(self, IpAddr::V4(_)) } /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] /// otherwise. /// /// [`IPv6` address]: IpAddr::V6 /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); /// ``` #[inline] pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr::V6(_)) } } impl Ipv4Addr { /// Creates a new IPv4 address from four eight-bit octets. /// /// The result will represent the IP address `a`.`b`.`c`.`d`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// ``` #[inline] pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { Ipv4Addr { inner: [a, b, c, d], } } /// An IPv4 address with the address pointing to localhost: `127.0.0.1` /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::LOCALHOST; /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); /// ``` pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); /// An IPv4 address representing an unspecified address: `0.0.0.0` /// /// This corresponds to the constant `INADDR_ANY` in other languages. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); /// ``` #[doc(alias = "INADDR_ANY")] pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); /// An IPv4 address representing the broadcast address: `255.255.255.255` /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::BROADCAST; /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); /// ``` pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); /// Returns the four eight-bit integers that make up this address. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` #[inline] pub const fn octets(&self) -> [u8; 4] { self.inner } /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); /// ``` #[inline] pub const fn is_unspecified(&self) -> bool { self.inner[0] == 0 && self.inner[1] == 0 && self.inner[2] == 0 && self.inner[3] == 0 } /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). /// /// This property is defined by [IETF RFC 1122]. /// /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` #[inline] pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 } /// Returns [`true`] if this is a private address. /// /// The private address ranges are defined in [IETF RFC 1918] and include: /// /// - `10.0.0.0/8` /// - `172.16.0.0/12` /// - `192.168.0.0/16` /// /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` #[inline] pub const fn is_private(&self) -> bool { match self.octets() { [10, ..] => true, [172, b, ..] if b >= 16 && b <= 31 => true, [192, 168, ..] => true, _ => false, } } /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). /// /// This property is defined by [IETF RFC 3927]. /// /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` #[inline] pub const fn is_link_local(&self) -> bool { matches!(self.octets(), [169, 254, ..]) } /// Returns [`true`] if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. /// /// The following return [`false`]: /// /// - private addresses (see [`Ipv4Addr::is_private()`]) /// - the loopback address (see [`Ipv4Addr::is_loopback()`]) /// - the link-local address (see [`Ipv4Addr::is_link_local()`]) /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`]) /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`]) /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole /// `0.0.0.0/8` block /// - addresses reserved for future protocols (see /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`] /// - addresses reserved for networking devices benchmarking (see /// [`Ipv4Addr::is_benchmarking()`]) /// /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv4Addr; /// /// // private addresses are not global /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); /// /// // the 0.0.0.0/8 block is not global /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); /// // in particular, the unspecified address is not global /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); /// /// // the loopback address is not global /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); /// /// // link local addresses are not global /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); /// /// // the broadcast address is not global /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); /// /// // the address space designated for documentation is not global /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); /// /// // shared addresses are not global /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); /// /// // addresses reserved for protocol assignment are not global /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); /// /// // addresses reserved for future use are not global /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); /// /// // addresses reserved for network devices benchmarking are not global /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); /// /// // All the other addresses are global /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two // globally routable addresses in the 192.0.0.0/24 range. if u32::from_be_bytes(self.octets()) == 0xc0000009 || u32::from_be_bytes(self.octets()) == 0xc000000a { return true; } !self.is_private() && !self.is_loopback() && !self.is_link_local() && !self.is_broadcast() && !self.is_documentation() && !self.is_shared() && !self.is_ietf_protocol_assignment() && !self.is_reserved() && !self.is_benchmarking() // Make sure the address is not in 0.0.0.0/8 && self.octets()[0] != 0 } /// Returns [`true`] if this address is part of the Shared Address Space defined in /// [IETF RFC 6598] (`100.64.0.0/10`). /// /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. /// /// Note that parts of this block are in use: /// /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) /// /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. /// /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since /// it is obviously not reserved for future use. /// /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 /// /// # Warning /// /// As IANA assigns new addresses, this method will be /// updated. This may result in non-reserved addresses being /// treated as reserved in code that relies on an outdated version /// of this method. /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); /// /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); /// // The broadcast address is not considered as reserved for future use by this implementation /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). /// /// Multicast addresses have a most significant octet between `224` and `239`, /// and is defined by [IETF RFC 5771]. /// /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` #[inline] pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 } /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). /// /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. /// /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` #[inline] pub const fn is_broadcast(&self) -> bool { u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) } /// Returns [`true`] if this address is in a range designated for documentation. /// /// This is defined in [IETF RFC 5737]: /// /// - `192.0.2.0/24` (TEST-NET-1) /// - `198.51.100.0/24` (TEST-NET-2) /// - `203.0.113.0/24` (TEST-NET-3) /// /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` #[inline] pub const fn is_documentation(&self) -> bool { match self.octets() { [192, 0, 2, _] => true, [198, 51, 100, _] => true, [203, 0, 113, _] => true, _ => false, } } /// Converts this address to an IPv4-compatible [`IPv6` address]. /// /// `a.b.c.d` becomes `::a.b.c.d` /// /// This isn't typically the method you want; these addresses don't typically /// function on modern systems. Use `to_ipv6_mapped` instead. /// /// [`IPv6` address]: Ipv6Addr /// /// # Examples /// /// ``` /// use no_std_net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!( /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) /// ); /// ``` #[inline] pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); Ipv6Addr::new( 0, 0, 0, 0, 0, 0, ((a as u16) << 8) | b as u16, ((c as u16) << 8) | d as u16, ) } /// Converts this address to an IPv4-mapped [`IPv6` address]. /// /// `a.b.c.d` becomes `::ffff:a.b.c.d` /// /// [`IPv6` address]: Ipv6Addr /// /// # Examples /// /// ``` /// use no_std_net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); /// ``` #[inline] pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); Ipv6Addr::new( 0, 0, 0, 0, 0, 0xffff, ((a as u16) << 8) | b as u16, ((c as u16) << 8) | d as u16, ) } } impl fmt::Display for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { IpAddr::V4(ip) => ip.fmt(fmt), IpAddr::V6(ip) => ip.fmt(fmt), } } } impl fmt::Debug for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl From for IpAddr { /// Copies this address to a new `IpAddr::V4`. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr}; /// /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// /// assert_eq!( /// IpAddr::V4(addr), /// IpAddr::from(addr) /// ) /// ``` #[inline] fn from(ipv4: Ipv4Addr) -> IpAddr { IpAddr::V4(ipv4) } } impl From for IpAddr { /// Copies this address to a new `IpAddr::V6`. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv6Addr}; /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// /// assert_eq!( /// IpAddr::V6(addr), /// IpAddr::from(addr) /// ); /// ``` #[inline] fn from(ipv6: Ipv6Addr) -> IpAddr { IpAddr::V6(ipv6) } } impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let octets = self.octets(); // Fast Path: if there's no alignment stuff, write directly to the buffer if fmt.precision().is_none() && fmt.width().is_none() { write!( fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3] ) } else { const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address let mut buf = [0u8; IPV4_BUF_LEN]; let mut buf_slice = WriteHelper::new(&mut buf[..]); // Note: The call to write should never fail, hence the unwrap write!( buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3] ) .unwrap(); let len = IPV4_BUF_LEN - buf_slice.into_raw().len(); // This unsafe is OK because we know what is being written to the buffer let buf = unsafe { core::str::from_utf8_unchecked(&buf[..len]) }; fmt.pad(buf) } } } impl fmt::Debug for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl Clone for Ipv4Addr { #[inline] fn clone(&self) -> Ipv4Addr { *self } } impl PartialEq for Ipv4Addr { #[inline] fn eq(&self, other: &Ipv4Addr) -> bool { self.inner == other.inner } } impl PartialEq for IpAddr { #[inline] fn eq(&self, other: &Ipv4Addr) -> bool { match self { IpAddr::V4(v4) => v4 == other, IpAddr::V6(_) => false, } } } impl PartialEq for Ipv4Addr { #[inline] fn eq(&self, other: &IpAddr) -> bool { match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } } } impl Eq for Ipv4Addr {} impl hash::Hash for Ipv4Addr { #[inline] fn hash(&self, s: &mut H) { self.inner.hash(s) } } impl PartialOrd for Ipv4Addr { #[inline] fn partial_cmp(&self, other: &Ipv4Addr) -> Option { Some(self.cmp(other)) } } impl PartialOrd for IpAddr { #[inline] fn partial_cmp(&self, other: &Ipv4Addr) -> Option { match self { IpAddr::V4(v4) => v4.partial_cmp(other), IpAddr::V6(_) => Some(Ordering::Greater), } } } impl PartialOrd for Ipv4Addr { #[inline] fn partial_cmp(&self, other: &IpAddr) -> Option { match other { IpAddr::V4(v4) => self.partial_cmp(v4), IpAddr::V6(_) => Some(Ordering::Less), } } } impl Ord for Ipv4Addr { #[inline] fn cmp(&self, other: &Ipv4Addr) -> Ordering { // Compare as native endian u32::from_be_bytes(self.inner).cmp(&u32::from_be_bytes(other.inner)) } } impl From for u32 { /// Converts an `Ipv4Addr` into a host byte order `u32`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe); /// assert_eq!(0xcafebabe, u32::from(addr)); /// ``` #[inline] fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); u32::from_be_bytes(ip) } } impl From for Ipv4Addr { /// Converts a host byte order `u32` into an `Ipv4Addr`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::from(0xcafebabe); /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr); /// ``` #[inline] fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::from(ip.to_be_bytes()) } } impl From<[u8; 4]> for Ipv4Addr { /// Creates an `Ipv4Addr` from a four element byte array. /// /// # Examples /// /// ``` /// use no_std_net::Ipv4Addr; /// /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); /// ``` #[inline] fn from(octets: [u8; 4]) -> Ipv4Addr { Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) } } impl From<[u8; 4]> for IpAddr { /// Creates an `IpAddr::V4` from a four element byte array. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv4Addr}; /// /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); /// ``` #[inline] fn from(octets: [u8; 4]) -> IpAddr { IpAddr::V4(Ipv4Addr::from(octets)) } } impl Ipv6Addr { /// Creates a new IPv6 address from eight 16-bit segments. /// /// The result will represent the IP address `a:b:c:d:e:f:g:h`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` #[inline] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { Ipv6Addr { inner: [ (a >> 8) as u8, a as u8, (b >> 8) as u8, b as u8, (c >> 8) as u8, c as u8, (d >> 8) as u8, d as u8, (e >> 8) as u8, e as u8, (f >> 8) as u8, f as u8, (g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8, ], } } /// An IPv6 address representing localhost: `::1`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::LOCALHOST; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// ``` pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); /// An IPv6 address representing the unspecified address: `::` /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); /// ``` pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); /// Returns the eight 16-bit segments that make up this address. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` #[inline] pub const fn segments(&self) -> [u16; 8] { let arr = self.octets(); [ (arr[0] as u16) << 8 | (arr[1] as u16), (arr[2] as u16) << 8 | (arr[3] as u16), (arr[4] as u16) << 8 | (arr[5] as u16), (arr[6] as u16) << 8 | (arr[7] as u16), (arr[8] as u16) << 8 | (arr[9] as u16), (arr[10] as u16) << 8 | (arr[11] as u16), (arr[12] as u16) << 8 | (arr[13] as u16), (arr[14] as u16) << 8 | (arr[15] as u16), ] } /// Returns [`true`] for the special 'unspecified' address (`::`). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` #[inline] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) } /// Returns [`true`] if this is a loopback address (::1). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` #[inline] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) } /// Returns [`true`] if the address appears to be globally routable. /// /// The following return [`false`]: /// /// - the loopback address /// - link-local and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), _ => false, } } /// Returns [`true`] if this is a unique local address (`fc00::/7`). /// /// This property is defined in [IETF RFC 4193]. /// /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [multicast address]: Ipv6Addr::is_multicast /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// // The unspecified and loopback addresses are unicast. /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); /// /// // Any address that is not a multicast address (`ff00::/8`) is unicast. /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_unicast(&self) -> bool { !self.is_multicast() } /// Returns `true` if the address is a unicast address with link-local scope, /// as defined in [RFC 4291]. /// /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: /// /// ```text /// | 10 bits | 54 bits | 64 bits | /// +----------+-------------------------+----------------------------+ /// |1111111010| 0 | interface ID | /// +----------+-------------------------+----------------------------+ /// ``` /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, /// and those addresses will have link-local scope. /// /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [loopback address]: Ipv6Addr::LOCALHOST /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// // The loopback address (`::1`) does not actually have link-local scope. /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); /// /// // Only addresses in `fe80::/10` have link-local scope. /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// /// // Addresses outside the stricter `fe80::/64` also have link-local scope. /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } /// Returns [`true`] if this is a deprecated unicast site-local address (`fec0::/10`). The /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: /// /// ```no_rust /// | 10 | /// | bits | 54 bits | 64 bits | /// +----------+-------------------------+----------------------------+ /// |1111111011| subnet ID | interface ID | /// +----------+-------------------------+----------------------------+ /// ``` /// /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// assert_eq!( /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), /// false /// ); /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); /// ``` /// /// # Warning /// /// As per [RFC 3879], the whole `fec0::/10` prefix is /// deprecated. New software must not support site-local /// addresses. /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } /// Returns [`true`] if this is an address reserved for documentation /// (`2001:db8::/32`). /// /// This property is defined in [IETF RFC 3849]. /// /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: /// /// - the loopback address /// - the link-local addresses /// - unique local addresses /// - the unspecified address /// - the address range reserved for documentation /// /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] /// /// ```no_rust /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer /// be supported in new implementations (i.e., new implementations must treat this prefix as /// Global Unicast). /// ``` /// /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn is_unicast_global(&self) -> bool { self.is_unicast() && !self.is_loopback() && !self.is_unicast_link_local() && !self.is_unique_local() && !self.is_unspecified() && !self.is_documentation() } /// Returns the address's multicast scope if the address is multicast. /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::{Ipv6Addr, Ipv6MulticastScope}; /// /// assert_eq!( /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), /// Some(Ipv6MulticastScope::Global) /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), 2 => Some(Ipv6MulticastScope::LinkLocal), 3 => Some(Ipv6MulticastScope::RealmLocal), 4 => Some(Ipv6MulticastScope::AdminLocal), 5 => Some(Ipv6MulticastScope::SiteLocal), 8 => Some(Ipv6MulticastScope::OrganizationLocal), 14 => Some(Ipv6MulticastScope::Global), _ => None, } } else { None } } /// Returns [`true`] if this is a multicast address (`ff00::/8`). /// /// This property is defined by [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` #[inline] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 } /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" /// defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// /// `::ffff:a.b.c.d` becomes `a.b.c.d`. /// All addresses *not* starting with `::ffff` will return `None`. /// /// [`IPv4` address]: Ipv4Addr /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 /// /// # Examples /// /// ``` /// // Requires `unstable_ip` feature /// /// use no_std_net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` #[cfg(feature = "unstable_ip")] #[inline] pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { Some(Ipv4Addr::new(a, b, c, d)) } _ => None, } } /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d` /// /// [`IPv4` address]: Ipv4Addr /// /// # Examples /// /// ``` /// use no_std_net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` #[inline] pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { let [a, b] = ab.to_be_bytes(); let [c, d] = cd.to_be_bytes(); Some(Ipv4Addr::new(a, b, c, d)) } else { None } } /// Returns the sixteen eight-bit integers the IPv6 address consists of. /// /// ``` /// use no_std_net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// ``` #[inline] pub const fn octets(&self) -> [u8; 16] { self.inner } } /// Write an Ipv6Addr, conforming to the canonical style described by /// [RFC 5952](https://tools.ietf.org/html/rfc5952). impl fmt::Display for Ipv6Addr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If there are no alignment requirements, write out the IP address to // f. Otherwise, write it to a local buffer, then use f.pad. if f.precision().is_none() && f.width().is_none() { let segments = self.segments(); // Special case for :: and ::1; otherwise they get written with the // IPv4 formatter if self.is_unspecified() { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") } else if let Some(ipv4) = self.to_ipv4() { match segments[5] { // IPv4 Compatible address 0 => write!(f, "::{}", ipv4), // IPv4 Mapped address 0xffff => write!(f, "::ffff:{}", ipv4), _ => unreachable!(), } } else { #[derive(Copy, Clone, Default)] struct Span { start: usize, len: usize, } // Find the inner 0 span let zeroes = { let mut longest = Span::default(); let mut current = Span::default(); for (i, &segment) in segments.iter().enumerate() { if segment == 0 { if current.len == 0 { current.start = i; } current.len += 1; if current.len > longest.len { longest = current; } } else { current = Span::default(); } } longest }; /// Write a colon-separated part of the address #[inline] fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { if let Some((first, tail)) = chunk.split_first() { write!(f, "{:x}", first)?; for segment in tail { f.write_char(':')?; write!(f, "{:x}", segment)?; } } Ok(()) } if zeroes.len > 1 { fmt_subslice(f, &segments[..zeroes.start])?; f.write_str("::")?; fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) } else { fmt_subslice(f, &segments) } } } else { // Slow path: write the address to a local buffer, the use f.pad. // Defined recursively by using the fast path to write to the // buffer. // This is the largest possible size of an IPv6 address const IPV6_BUF_LEN: usize = (4 * 8) + 7; let mut buf = [0u8; IPV6_BUF_LEN]; let mut buf_slice = WriteHelper::new(&mut buf[..]); // Note: This call to write should never fail, so unwrap is okay. write!(buf_slice, "{}", self).unwrap(); let len = IPV6_BUF_LEN - buf_slice.into_raw().len(); // This is safe because we know exactly what can be in this buffer let buf = unsafe { core::str::from_utf8_unchecked(&buf[..len]) }; f.pad(buf) } } } impl fmt::Debug for Ipv6Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl Clone for Ipv6Addr { #[inline] fn clone(&self) -> Ipv6Addr { *self } } impl PartialEq for Ipv6Addr { #[inline] fn eq(&self, other: &Ipv6Addr) -> bool { self.inner == other.inner } } impl PartialEq for Ipv6Addr { #[inline] fn eq(&self, other: &IpAddr) -> bool { match other { IpAddr::V4(_) => false, IpAddr::V6(v6) => self == v6, } } } impl PartialEq for IpAddr { #[inline] fn eq(&self, other: &Ipv6Addr) -> bool { match self { IpAddr::V4(_) => false, IpAddr::V6(v6) => v6 == other, } } } impl Eq for Ipv6Addr {} impl hash::Hash for Ipv6Addr { #[inline] fn hash(&self, s: &mut H) { self.inner.hash(s) } } impl PartialOrd for Ipv6Addr { #[inline] fn partial_cmp(&self, other: &Ipv6Addr) -> Option { Some(self.cmp(other)) } } impl PartialOrd for IpAddr { #[inline] fn partial_cmp(&self, other: &Ipv6Addr) -> Option { match self { IpAddr::V4(_) => Some(Ordering::Less), IpAddr::V6(v6) => v6.partial_cmp(other), } } } impl PartialOrd for Ipv6Addr { #[inline] fn partial_cmp(&self, other: &IpAddr) -> Option { match other { IpAddr::V4(_) => Some(Ordering::Greater), IpAddr::V6(v6) => self.partial_cmp(v6), } } } impl Ord for Ipv6Addr { #[inline] fn cmp(&self, other: &Ipv6Addr) -> Ordering { self.segments().cmp(&other.segments()) } } impl From for u128 { /// Convert an `Ipv6Addr` into a host byte order `u128`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::new( /// 0x1020, 0x3040, 0x5060, 0x7080, /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, /// ); /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); /// ``` #[inline] fn from(ip: Ipv6Addr) -> u128 { let ip = ip.octets(); u128::from_be_bytes(ip) } } impl From for Ipv6Addr { /// Convert a host byte order `u128` into an `Ipv6Addr`. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); /// assert_eq!( /// Ipv6Addr::new( /// 0x1020, 0x3040, 0x5060, 0x7080, /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, /// ), /// addr); /// ``` #[inline] fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::from(ip.to_be_bytes()) } } impl From<[u8; 16]> for Ipv6Addr { /// Creates an `Ipv6Addr` from a sixteen element byte array. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::from([ /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, /// ]); /// assert_eq!( /// Ipv6Addr::new( /// 0x1918, 0x1716, /// 0x1514, 0x1312, /// 0x1110, 0x0f0e, /// 0x0d0c, 0x0b0a /// ), /// addr /// ); /// ``` #[inline] fn from(octets: [u8; 16]) -> Ipv6Addr { Ipv6Addr { inner: octets } } } impl From<[u16; 8]> for Ipv6Addr { /// Creates an `Ipv6Addr` from an eight element 16-bit array. /// /// # Examples /// /// ``` /// use no_std_net::Ipv6Addr; /// /// let addr = Ipv6Addr::from([ /// 525u16, 524u16, 523u16, 522u16, /// 521u16, 520u16, 519u16, 518u16, /// ]); /// assert_eq!( /// Ipv6Addr::new( /// 0x20d, 0x20c, /// 0x20b, 0x20a, /// 0x209, 0x208, /// 0x207, 0x206 /// ), /// addr /// ); /// ``` #[inline] fn from(segments: [u16; 8]) -> Ipv6Addr { let [a, b, c, d, e, f, g, h] = segments; Ipv6Addr::new(a, b, c, d, e, f, g, h) } } impl From<[u8; 16]> for IpAddr { /// Creates an `IpAddr::V6` from a sixteen element byte array. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv6Addr}; /// /// let addr = IpAddr::from([ /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, /// ]); /// assert_eq!( /// IpAddr::V6(Ipv6Addr::new( /// 0x1918, 0x1716, /// 0x1514, 0x1312, /// 0x1110, 0x0f0e, /// 0x0d0c, 0x0b0a /// )), /// addr /// ); /// ``` #[inline] fn from(octets: [u8; 16]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(octets)) } } impl From<[u16; 8]> for IpAddr { /// Creates an `IpAddr::V6` from an eight element 16-bit array. /// /// # Examples /// /// ``` /// use no_std_net::{IpAddr, Ipv6Addr}; /// /// let addr = IpAddr::from([ /// 525u16, 524u16, 523u16, 522u16, /// 521u16, 520u16, 519u16, 518u16, /// ]); /// assert_eq!( /// IpAddr::V6(Ipv6Addr::new( /// 0x20d, 0x20c, /// 0x20b, 0x20a, /// 0x209, 0x208, /// 0x207, 0x206 /// )), /// addr /// ); /// ``` #[inline] fn from(segments: [u16; 8]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } } no-std-net-0.6.0/src/lib.rs000064400000000000000000000063440072674642500135610ustar 00000000000000// Effectively all the code in this repo is copied with permission from Rust's std library. // They hold the copyright (http://rust-lang.org/COPYRIGHT) and whatever other rights, but this // crate is MIT licensed also, so it's all good. //! Networking primitives for TCP/UDP communication. //! //! This module provides networking functionality for the Transmission Control and User //! Datagram Protocols, as well as types for IP and socket addresses. It has been ported //! from std::net to remove the dependency on std. //! //! This crate is a WIP, issues, feedback and PRs are welcome as long as they follow the theme of //! "std::net" clone. //! //! # Organization //! //! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and //! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses //! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP //! * [`UdpSocket`] provides functionality for communication over UDP //! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] //! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses //! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting //! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] //! * Other types are return or parameter types for various methods in this module //! #![cfg_attr(feature = "std", doc = "[`TcpListener`]: std::net::TcpListener")] #![cfg_attr(feature = "std", doc = "[`TcpStream`]: std::net::TcpStream")] #![cfg_attr(feature = "std", doc = "[`UdpSocket`]: std::net::UdpSocket")] #![cfg_attr( not(feature = "std"), doc = "[`TcpListener`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html" )] #![cfg_attr( not(feature = "std"), doc = "[`TcpStream`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html" )] #![cfg_attr( not(feature = "std"), doc = "[`UdpSocket`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html" )] #![no_std] #![deny( dead_code, missing_docs, unused_imports, unused_must_use, unused_parens, unused_qualifications, warnings )] #![cfg_attr(all(feature = "std", feature = "unstable_ip"), feature(ip))] #[cfg(not(feature = "std"))] mod addr; #[cfg(not(feature = "std"))] mod helper; #[cfg(not(feature = "std"))] mod ip; #[cfg(not(feature = "std"))] mod parser; #[cfg(all(not(feature = "std"), test))] mod test; #[cfg(all(not(feature = "std"), test))] #[macro_use] extern crate alloc; #[cfg(all(not(feature = "std"), feature = "serde"))] extern crate serde; #[cfg(all(not(feature = "std"), feature = "serde"))] mod de; #[cfg(all(not(feature = "std"), feature = "serde"))] mod ser; #[cfg(not(feature = "std"))] pub use addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; #[cfg(all(not(feature = "std"), feature = "unstable_ip"))] pub use ip::Ipv6MulticastScope; #[cfg(not(feature = "std"))] pub use ip::{IpAddr, Ipv4Addr, Ipv6Addr}; // Re-export std::net types when std is available #[cfg(feature = "std")] extern crate std; #[cfg(all(feature = "std", feature = "unstable_ip"))] pub use std::net::Ipv6MulticastScope; #[cfg(feature = "std")] pub use std::net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, }; no-std-net-0.6.0/src/parser/tests.rs000064400000000000000000000126450072674642500154520ustar 00000000000000// FIXME: These tests are all excellent candidates for AFL fuzz testing use crate::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use core::str::FromStr; const PORT: u16 = 8080; const SCOPE_ID: u32 = 1337; const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); const IPV4_STR: &str = "192.168.0.1"; const IPV4_STR_PORT: &str = "192.168.0.1:8080"; const IPV4_STR_WITH_OCTAL: &str = "0127.0.0.1"; const IPV4_STR_WITH_HEX: &str = "0x10.0.0.1"; const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; const IPV6_STR_V4_WITH_OCTAL: &str = "2001:db8::0127.0.0.1"; const IPV6_STR_V4_WITH_HEX: &str = "2001:db8::0x10.0.0.1"; const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; #[test] fn parse_ipv4() { let result: Ipv4Addr = IPV4_STR.parse().unwrap(); assert_eq!(result, IPV4); assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); assert!(Ipv4Addr::from_str(IPV4_STR_WITH_OCTAL).is_err()); assert!(Ipv4Addr::from_str(IPV4_STR_WITH_HEX).is_err()); assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); } #[test] fn parse_ipv6() { let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); assert_eq!(result, IPV6); let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); assert_eq!(result, IPV6); let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); assert_eq!(result, IPV6); assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_OCTAL).is_err()); assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_HEX).is_err()); assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); } #[test] fn parse_ip() { let result: IpAddr = IPV4_STR.parse().unwrap(); assert_eq!(result, IpAddr::from(IPV4)); let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); assert_eq!(result, IpAddr::from(IPV6)); let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); assert_eq!(result, IpAddr::from(IPV6)); let result: IpAddr = IPV6_STR_V4.parse().unwrap(); assert_eq!(result, IpAddr::from(IPV6)); assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); } #[test] fn parse_socket_v4() { let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); } #[test] fn parse_socket_v6() { assert_eq!( IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0)) ); assert_eq!( IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID)) ); assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); } #[test] fn parse_socket() { let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); assert_eq!(result, SocketAddr::from((IPV4, PORT))); let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); assert_eq!(result, SocketAddr::from((IPV6, PORT))); assert!(SocketAddr::from_str(IPV4_STR).is_err()); assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); } #[test] fn ipv6_corner_cases() { let result: Ipv6Addr = "1::".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); let result: Ipv6Addr = "1:1::".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); let result: Ipv6Addr = "::1".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); let result: Ipv6Addr = "::1:1".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); let result: Ipv6Addr = "::".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); } // Things that might not seem like failures but are #[test] fn ipv6_corner_failures() { // No IP address before the :: assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); // :: must have at least 1 set of zeroes assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); // Need brackets for a port assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); } no-std-net-0.6.0/src/parser.rs000064400000000000000000000266630072674642500143150ustar 00000000000000// Effectively all the code in this repo is copied with permission from Rust's std library. // They hold the copyright (http://rust-lang.org/COPYRIGHT) and whatever other rights, but this // crate is MIT licensed also, so it's all good. //! A private parser implementation of IPv4, IPv6, and socket addresses. //! //! This module is "publicly exported" through the `FromStr` implementations //! below. #[cfg(test)] mod tests; use core::convert::TryInto; use core::fmt; use core::str::FromStr; use super::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; trait ReadNumberHelper: Sized { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; } macro_rules! impl_helper { ($($t:ty)*) => ($(impl ReadNumberHelper for $t { const ZERO: Self = 0; #[inline] fn checked_mul(&self, other: u32) -> Option { Self::checked_mul(*self, other.try_into().ok()?) } #[inline] fn checked_add(&self, other: u32) -> Option { Self::checked_add(*self, other.try_into().ok()?) } })*) } impl_helper! { u8 u16 u32 } struct Parser<'a> { // Parsing as ASCII, so can use byte array. state: &'a [u8], } impl<'a> Parser<'a> { fn new(input: &'a str) -> Parser<'a> { Parser { state: input.as_bytes(), } } /// Run a parser, and restore the pre-parse state if it fails. fn read_atomically(&mut self, inner: F) -> Option where F: FnOnce(&mut Parser<'_>) -> Option, { let state = self.state; let result = inner(self); if result.is_none() { self.state = state; } result } /// Run a parser, but fail if the entire input wasn't consumed. /// Doesn't run atomically. fn parse_with(&mut self, inner: F) -> Result where F: FnOnce(&mut Parser<'_>) -> Option, { let result = inner(self); if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(())) } /// Peek the next character from the input fn peek_char(&self) -> Option { self.state.first().map(|&b| char::from(b)) } /// Read the next character from the input fn read_char(&mut self) -> Option { self.state.split_first().map(|(&b, tail)| { self.state = tail; char::from(b) }) } #[must_use] /// Read the next character from the input if it matches the target. fn read_given_char(&mut self, target: char) -> Option<()> { self.read_atomically(|p| { p.read_char() .and_then(|c| if c == target { Some(()) } else { None }) }) } /// Helper for reading separators in an indexed loop. Reads the separator /// character iff index > 0, then runs the parser. When used in a loop, /// the separator character will only be read on index > 0 (see /// read_ipv4_addr for an example) fn read_separator(&mut self, sep: char, index: usize, inner: F) -> Option where F: FnOnce(&mut Parser<'_>) -> Option, { self.read_atomically(move |p| { if index > 0 { p.read_given_char(sep)?; } inner(p) }) } // Read a number off the front of the input in the given radix, stopping // at the first non-digit character or eof. Fails if the number has more // digits than max_digits or if there is no number. fn read_number( &mut self, radix: u32, max_digits: Option, ) -> Option { self.read_atomically(move |p| { let mut result = T::ZERO; let mut digit_count = 0; while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { result = result.checked_mul(radix)?; result = result.checked_add(digit)?; digit_count += 1; if let Some(max_digits) = max_digits { if digit_count > max_digits { return None; } } } if digit_count == 0 { None } else { Some(result) } }) } /// Read an IPv4 address. fn read_ipv4_addr(&mut self) -> Option { self.read_atomically(|p| { let mut groups = [0; 4]; for (i, slot) in groups.iter_mut().enumerate() { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 match (p.peek_char(), p.read_number(10, None)) { (Some('0'), Some(number)) if number != 0 => None, (_, number) => number, } })?; } Some(groups.into()) }) } /// Read an IPv6 Address. fn read_ipv6_addr(&mut self) -> Option { /// Read a chunk of an IPv6 address into `groups`. Returns the number /// of groups read, along with a bool indicating if an embedded /// trailing IPv4 address was read. Specifically, read a series of /// colon-separated IPv6 groups (0x0000 - 0xFFFF), with an optional /// trailing embedded IPv4 address. fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) { let limit = groups.len(); for (i, slot) in groups.iter_mut().enumerate() { // Try to read a trailing embedded IPv4 address. There must be // at least two groups left. if i < limit - 1 { let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr()); if let Some(v4_addr) = ipv4 { let [one, two, three, four] = v4_addr.octets(); groups[i + 0] = u16::from_be_bytes([one, two]); groups[i + 1] = u16::from_be_bytes([three, four]); return (i + 2, true); } } let group = p.read_separator(':', i, |p| p.read_number(16, Some(4))); match group { Some(g) => *slot = g, None => return (i, false), } } (groups.len(), false) } self.read_atomically(|p| { // Read the front part of the address; either the whole thing, or up // to the first :: let mut head = [0; 8]; let (head_size, head_ipv4) = read_groups(p, &mut head); if head_size == 8 { return Some(head.into()); } // IPv4 part is not allowed before `::` if head_ipv4 { return None; } // Read `::` if previous code parsed less than 8 groups. // `::` indicates one or more groups of 16 bits of zeros. p.read_given_char(':')?; p.read_given_char(':')?; // Read the back part of the address. The :: must contain at least one // set of zeroes, so our max length is 7. let mut tail = [0; 7]; let limit = 8 - (head_size + 1); let (tail_size, _) = read_groups(p, &mut tail[..limit]); // Concat the head and tail of the IP address head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]); Some(head.into()) }) } /// Read an IP Address, either IPv4 or IPv6. fn read_ip_addr(&mut self) -> Option { self.read_ipv4_addr() .map(IpAddr::V4) .or_else(move || self.read_ipv6_addr().map(IpAddr::V6)) } /// Read a `:` followed by a port in base 10. fn read_port(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char(':')?; p.read_number(10, None) }) } /// Read a `%` followed by a scope ID in base 10. fn read_scope_id(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('%')?; p.read_number(10, None) }) } /// Read an IPv4 address with a port. fn read_socket_addr_v4(&mut self) -> Option { self.read_atomically(|p| { let ip = p.read_ipv4_addr()?; let port = p.read_port()?; Some(SocketAddrV4::new(ip, port)) }) } /// Read an IPv6 address with a port. fn read_socket_addr_v6(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('[')?; let ip = p.read_ipv6_addr()?; let scope_id = p.read_scope_id().unwrap_or(0); p.read_given_char(']')?; let port = p.read_port()?; Some(SocketAddrV6::new(ip, port, 0, scope_id)) }) } /// Read an IP address with a port fn read_socket_addr(&mut self) -> Option { self.read_socket_addr_v4() .map(SocketAddr::V4) .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6)) } } impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_ip_addr()) } } impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_ipv4_addr()) } } impl FromStr for Ipv6Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_ipv6_addr()) } } impl FromStr for SocketAddrV4 { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_socket_addr_v4()) } } impl FromStr for SocketAddrV6 { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_socket_addr_v6()) } } impl FromStr for SocketAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { Parser::new(s).parse_with(|p| p.read_socket_addr()) } } /// An error which can be returned when parsing an IP address or a socket address. /// /// This error is used as the error type for the [`FromStr`] implementation for /// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and /// [`SocketAddrV6`]. /// /// # Potential causes /// /// `AddrParseError` may be thrown because the provided string does not parse as the given type, /// often because it includes information only handled by a different address type. /// /// ```should_panic /// use no_std_net::IpAddr; /// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); /// ``` /// /// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. /// /// ``` /// use no_std_net::SocketAddr; /// /// // No problem, the `panic!` message has disappeared. /// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); /// ``` #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddrParseError(()); impl fmt::Display for AddrParseError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str("invalid IP address syntax") } } no-std-net-0.6.0/src/ser.rs000064400000000000000000000312040072674642500135750ustar 00000000000000use serde::ser::{Error, Serialize, Serializer}; use addr::{SocketAddr, SocketAddrV4, SocketAddrV6}; use ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use core::fmt::{self, write, Write}; struct Wrapper<'a> { buf: &'a mut [u8], offset: usize, } impl<'a> Wrapper<'a> { fn new(buf: &'a mut [u8]) -> Self { Wrapper { buf, offset: 0 } } pub fn as_str(self) -> Option<&'a str> { if self.offset <= self.buf.len() { match core::str::from_utf8(&self.buf[..self.offset]) { Ok(s) => Some(s), Err(_) => None, } } else { None } } } impl<'a> Write for Wrapper<'a> { fn write_str(&mut self, s: &str) -> fmt::Result { if self.offset > self.buf.len() { return Err(fmt::Error); } let remaining_buf = &mut self.buf[self.offset..]; let raw_s = s.as_bytes(); let write_num = core::cmp::min(raw_s.len(), remaining_buf.len()); remaining_buf[..write_num].copy_from_slice(&raw_s[..write_num]); self.offset += raw_s.len(); if write_num < raw_s.len() { Err(fmt::Error) } else { Ok(()) } } } macro_rules! serialize_display_bounded_length { ($value:expr, $max:expr, $serializer:expr) => {{ let mut buffer: [u8; $max] = [0u8; $max]; let mut w = Wrapper::new(&mut buffer); write(&mut w, format_args!("{}", $value)).map_err(Error::custom)?; if let Some(s) = w.as_str() { $serializer.serialize_str(s) } else { Err(Error::custom("Failed to parse str to UTF8")) } }}; } impl Serialize for IpAddr { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { match *self { IpAddr::V4(ref a) => a.serialize(serializer), IpAddr::V6(ref a) => a.serialize(serializer), } } else { match *self { IpAddr::V4(ref a) => serializer.serialize_newtype_variant("IpAddr", 0, "V4", a), IpAddr::V6(ref a) => serializer.serialize_newtype_variant("IpAddr", 1, "V6", a), } } } } impl Serialize for Ipv4Addr { fn serialize(&self, serializer: S) -> Result where S: Serializer, S::Error: Error, { if serializer.is_human_readable() { const MAX_LEN: usize = 15; debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { self.octets().serialize(serializer) } } } impl Serialize for Ipv6Addr { fn serialize(&self, serializer: S) -> Result where S: Serializer, S::Error: Error, { if serializer.is_human_readable() { const MAX_LEN: usize = 39; debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len()); serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { self.octets().serialize(serializer) } } } impl Serialize for SocketAddr { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { match *self { SocketAddr::V4(ref addr) => addr.serialize(serializer), SocketAddr::V6(ref addr) => addr.serialize(serializer), } } else { match *self { SocketAddr::V4(ref addr) => { serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr) } SocketAddr::V6(ref addr) => { serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr) } } } } } impl Serialize for SocketAddrV4 { fn serialize(&self, serializer: S) -> Result where S: Serializer, S::Error: Error, { if serializer.is_human_readable() { const MAX_LEN: usize = 21; debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len()); serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { (self.ip(), self.port()).serialize(serializer) } } } impl Serialize for SocketAddrV6 { fn serialize(&self, serializer: S) -> Result where S: Serializer, S::Error: Error, { if serializer.is_human_readable() { const MAX_LEN: usize = 47; debug_assert_eq!( MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len() ); serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { (self.ip(), self.port()).serialize(serializer) } } } #[cfg(test)] mod tests { extern crate serde_test; use self::serde_test::{assert_tokens, Configure, Token}; use super::*; #[test] fn serialize_ipv4() { assert_tokens( &Ipv4Addr::new(101, 102, 103, 104).readable(), &[Token::Str("101.102.103.104")], ); assert_tokens( &Ipv4Addr::new(101, 102, 103, 104).compact(), &[ Token::Tuple { len: 4 }, Token::U8(101), Token::U8(102), Token::U8(103), Token::U8(104), Token::TupleEnd, ], ); } #[test] fn serialize_ipaddr_v4() { assert_tokens( &IpAddr::V4(Ipv4Addr::new(101, 102, 103, 104)).readable(), &[Token::Str("101.102.103.104")], ); assert_tokens( &Ipv4Addr::new(101, 102, 103, 104).compact(), &[ Token::Tuple { len: 4 }, Token::U8(101), Token::U8(102), Token::U8(103), Token::U8(104), Token::TupleEnd, ], ); } #[test] fn serialize_ipaddr_v6() { assert_tokens( &IpAddr::V6(Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, )) .readable(), &[Token::Str("1020:3040:5060:7080:90a0:b0c0:d0e0:f00d")], ); assert_tokens( &IpAddr::V6(Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, )) .compact(), &[ Token::NewtypeVariant { name: "IpAddr", variant: "V6", }, Token::Tuple { len: 16 }, Token::U8(16), Token::U8(32), Token::U8(48), Token::U8(64), Token::U8(80), Token::U8(96), Token::U8(112), Token::U8(128), Token::U8(144), Token::U8(160), Token::U8(176), Token::U8(192), Token::U8(208), Token::U8(224), Token::U8(240), Token::U8(13), Token::TupleEnd, ], ); } #[test] fn serialize_ipv6() { assert_tokens( &Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ) .readable(), &[Token::Str("1020:3040:5060:7080:90a0:b0c0:d0e0:f00d")], ); assert_tokens( &Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ) .compact(), &[ Token::Tuple { len: 16 }, Token::U8(16), Token::U8(32), Token::U8(48), Token::U8(64), Token::U8(80), Token::U8(96), Token::U8(112), Token::U8(128), Token::U8(144), Token::U8(160), Token::U8(176), Token::U8(192), Token::U8(208), Token::U8(224), Token::U8(240), Token::U8(13), Token::TupleEnd, ], ); } #[test] fn serialize_socketv4() { assert_tokens( &SocketAddrV4::new(Ipv4Addr::new(101, 102, 103, 104), 443).readable(), &[Token::Str("101.102.103.104:443")], ); assert_tokens( &SocketAddrV4::new(Ipv4Addr::new(101, 102, 103, 104), 443).compact(), &[ Token::Tuple { len: 2 }, Token::Tuple { len: 4 }, Token::U8(101), Token::U8(102), Token::U8(103), Token::U8(104), Token::TupleEnd, Token::U16(443), Token::TupleEnd, ], ); } #[test] fn serialize_socket_addr_v4() { assert_tokens( &SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(101, 102, 103, 104), 443)).readable(), &[Token::Str("101.102.103.104:443")], ); assert_tokens( &SocketAddrV4::new(Ipv4Addr::new(101, 102, 103, 104), 443).compact(), &[ Token::Tuple { len: 2 }, Token::Tuple { len: 4 }, Token::U8(101), Token::U8(102), Token::U8(103), Token::U8(104), Token::TupleEnd, Token::U16(443), Token::TupleEnd, ], ); } #[test] fn serialize_socket_addr_v6() { assert_tokens( &SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ), 443, 0, 0, )) .readable(), &[Token::Str("[1020:3040:5060:7080:90a0:b0c0:d0e0:f00d]:443")], ); assert_tokens( &SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ), 443, 0, 0, )) .compact(), &[ Token::NewtypeVariant { name: "SocketAddr", variant: "V6", }, Token::Tuple { len: 2 }, Token::Tuple { len: 16 }, Token::U8(16), Token::U8(32), Token::U8(48), Token::U8(64), Token::U8(80), Token::U8(96), Token::U8(112), Token::U8(128), Token::U8(144), Token::U8(160), Token::U8(176), Token::U8(192), Token::U8(208), Token::U8(224), Token::U8(240), Token::U8(13), Token::TupleEnd, Token::U16(443), Token::TupleEnd, ], ); } #[test] fn serialize_socketv6() { assert_tokens( &SocketAddrV6::new( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ), 443, 0, 0, ) .readable(), &[Token::Str("[1020:3040:5060:7080:90a0:b0c0:d0e0:f00d]:443")], ); assert_tokens( &SocketAddrV6::new( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ), 443, 0, 0, ) .compact(), &[ Token::Tuple { len: 2 }, Token::Tuple { len: 16 }, Token::U8(16), Token::U8(32), Token::U8(48), Token::U8(64), Token::U8(80), Token::U8(96), Token::U8(112), Token::U8(128), Token::U8(144), Token::U8(160), Token::U8(176), Token::U8(192), Token::U8(208), Token::U8(224), Token::U8(240), Token::U8(13), Token::TupleEnd, Token::U16(443), Token::TupleEnd, ], ); } } no-std-net-0.6.0/src/test.rs000064400000000000000000000007340072674642500137670ustar 00000000000000use alloc::vec::Vec; use super::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { SocketAddr::V4(SocketAddrV4::new(a, p)) } pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) } pub fn tsa(a: A) -> Result, ()> { match a.to_socket_addrs() { Ok(a) => Ok(a.collect()), Err(_) => Err(()), } }