diff options
| author | Fenrir <[email protected]> | 2018-01-21 14:06:28 -0700 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-01-21 19:16:33 -0700 |
| commit | 23be3f4885688e5e0011005e2295c75168854c0a (patch) | |
| tree | dd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/net | |
| parent | Update CI for Rust nightly-2017-12-01 + other fixes (diff) | |
| download | archived-ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz archived-ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip | |
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/net')
| -rw-r--r-- | ctr-std/src/net/addr.rs | 1067 | ||||
| -rw-r--r-- | ctr-std/src/net/ip.rs | 1835 | ||||
| -rw-r--r-- | ctr-std/src/net/mod.rs | 186 | ||||
| -rw-r--r-- | ctr-std/src/net/parser.rs | 398 | ||||
| -rw-r--r-- | ctr-std/src/net/tcp.rs | 1662 | ||||
| -rw-r--r-- | ctr-std/src/net/test.rs | 57 | ||||
| -rw-r--r-- | ctr-std/src/net/udp.rs | 1116 |
7 files changed, 6321 insertions, 0 deletions
diff --git a/ctr-std/src/net/addr.rs b/ctr-std/src/net/addr.rs new file mode 100644 index 0000000..1ca7e66 --- /dev/null +++ b/ctr-std/src/net/addr.rs @@ -0,0 +1,1067 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use hash; +use io; +use mem; +use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +use option; +use sys::net::netc as c; +use sys_common::{FromInner, AsInner, IntoInner}; +use vec; +use iter; +use slice; + +/// 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]: ../../std/net/enum.IpAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// +/// # Examples +/// +/// ``` +/// use 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, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub enum SocketAddr { + /// An IPv4 socket address. + #[stable(feature = "rust1", since = "1.0.0")] + V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), + /// An IPv6 socket address. + #[stable(feature = "rust1", since = "1.0.0")] + V6(#[stable(feature = "rust1", since = "1.0.0")] 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]: ../../std/net/struct.Ipv4Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use 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)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SocketAddrV4 { inner: c::sockaddr_in } + +/// 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]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use 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)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SocketAddrV6 { inner: c::sockaddr_in6 } + +impl SocketAddr { + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: ../../std/net/enum.IpAddr.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "ip_addr", since = "1.7.0")] + pub 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 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))); + /// ``` + #[stable(feature = "ip_addr", since = "1.7.0")] + pub 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 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))); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + 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 std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub 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 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); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + 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. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + #[stable(feature = "sockaddr_checker", since = "1.16.0")] + pub fn is_ipv4(&self) -> bool { + match *self { + SocketAddr::V4(_) => true, + SocketAddr::V6(_) => false, + } + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv6 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + #[stable(feature = "sockaddr_checker", since = "1.16.0")] + pub fn is_ipv6(&self) -> bool { + match *self { + SocketAddr::V4(_) => false, + SocketAddr::V6(_) => true, + } + } +} + +impl SocketAddrV4 { + /// Creates a new socket address from an [IPv4 address] and a port number. + /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { + SocketAddrV4 { + inner: c::sockaddr_in { + sin_family: c::AF_INET as c::sa_family_t, + sin_port: hton(port), + sin_addr: *ip.as_inner(), + .. unsafe { mem::zeroed() } + }, + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ip(&self) -> &Ipv4Addr { + unsafe { + &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr) + } + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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)); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + self.inner.sin_addr = *new_ip.as_inner() + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn port(&self) -> u16 { + ntoh(self.inner.sin_port) + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_port(&mut self, new_port: u16) { + self.inner.sin_port = hton(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]: ../../std/net/struct.Ipv6Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) + -> SocketAddrV6 { + SocketAddrV6 { + inner: c::sockaddr_in6 { + sin6_family: c::AF_INET6 as c::sa_family_t, + sin6_port: hton(port), + sin6_addr: *ip.as_inner(), + sin6_flowinfo: flowinfo, + sin6_scope_id: scope_id, + .. unsafe { mem::zeroed() } + }, + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ip(&self) -> &Ipv6Addr { + unsafe { + &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr) + } + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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)); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + self.inner.sin6_addr = *new_ip.as_inner() + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn port(&self) -> u16 { + ntoh(self.inner.sin6_port) + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_port(&mut self, new_port: u16) { + self.inner.sin6_port = hton(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 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); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn flowinfo(&self) -> u32 { + self.inner.sin6_flowinfo + } + + /// Changes the flow information associated with this socket address. + /// + /// See the [`flowinfo`] method's documentation for more details. + /// + /// [`flowinfo`]: #method.flowinfo + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + self.inner.sin6_flowinfo = 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 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); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn scope_id(&self) -> u32 { + self.inner.sin6_scope_id + } + + /// Change the scope ID associated with this socket address. + /// + /// See the [`scope_id`] method's documentation for more details. + /// + /// [`scope_id`]: #method.scope_id + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_scope_id(&mut self, new_scope_id: u32) { + self.inner.sin6_scope_id = new_scope_id; + } +} + +impl FromInner<c::sockaddr_in> for SocketAddrV4 { + fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { + SocketAddrV4 { inner: addr } + } +} + +impl FromInner<c::sockaddr_in6> for SocketAddrV6 { + fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { + SocketAddrV6 { inner: addr } + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<SocketAddrV4> for SocketAddr { + fn from(sock4: SocketAddrV4) -> SocketAddr { + SocketAddr::V4(sock4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<SocketAddrV6> for SocketAddr { + fn from(sock6: SocketAddrV6) -> SocketAddr { + SocketAddr::V6(sock6) + } +} + +#[stable(feature = "addr_from_into_ip", since = "1.17.0")] +impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr { + fn from(pieces: (I, u16)) -> SocketAddr { + SocketAddr::new(pieces.0.into(), pieces.1) + } +} + +impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr { + fn into_inner(self) -> (*const c::sockaddr, c::socklen_t) { + match *self { + SocketAddr::V4(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + SocketAddr::V6(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +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), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddrV4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}:{}", self.ip(), self.port()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for SocketAddrV4 { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddrV6 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}]:{}", self.ip(), self.port()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for SocketAddrV6 { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for SocketAddrV4 { + fn clone(&self) -> SocketAddrV4 { *self } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for SocketAddrV6 { + fn clone(&self) -> SocketAddrV6 { *self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for SocketAddrV4 { + fn eq(&self, other: &SocketAddrV4) -> bool { + self.inner.sin_port == other.inner.sin_port && + self.inner.sin_addr.s_addr == other.inner.sin_addr.s_addr + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for SocketAddrV6 { + fn eq(&self, other: &SocketAddrV6) -> bool { + self.inner.sin6_port == other.inner.sin6_port && + self.inner.sin6_addr.s6_addr == other.inner.sin6_addr.s6_addr && + self.inner.sin6_flowinfo == other.inner.sin6_flowinfo && + self.inner.sin6_scope_id == other.inner.sin6_scope_id + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for SocketAddrV4 {} +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for SocketAddrV6 {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for SocketAddrV4 { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + (self.inner.sin_port, self.inner.sin_addr.s_addr).hash(s) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for SocketAddrV6 { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + (self.inner.sin6_port, &self.inner.sin6_addr.s6_addr, + self.inner.sin6_flowinfo, self.inner.sin6_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`]`)`: the string should be either a string representation +/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host +/// name. +/// +/// * [`&str`]: the string should be either a string representation of a +/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like +/// `<host_name>:<port>` pair where `<port>` 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`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// [`&str`]: ../../std/primitive.str.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// [`to_socket_addrs`]: #tymethod.to_socket_addrs +/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html +/// [`u16`]: ../../std/primitive.u16.html +/// +/// # Examples +/// +/// Creating a [`SocketAddr`] iterator that yields one item: +/// +/// ``` +/// use 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 from a hostname: +/// +/// ```no_run +/// use std::net::{SocketAddr, ToSocketAddrs}; +/// +/// // assuming 'localhost' resolves to 127.0.0.1 +/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap(); +/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443)))); +/// assert!(addrs_iter.next().is_none()); +/// +/// // assuming 'foo' does not resolve +/// assert!("foo:443".to_socket_addrs().is_err()); +/// ``` +/// +/// Creating a [`SocketAddr`] iterator that yields multiple items: +/// +/// ``` +/// use 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()); +/// ``` +/// +/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted +/// socket address `&str` (missing the port): +/// +/// ``` +/// use std::io; +/// use std::net::ToSocketAddrs; +/// +/// let err = "127.0.0.1".to_socket_addrs().unwrap_err(); +/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); +/// ``` +/// +/// [`TcpStream::connect`] is an example of an function that utilizes +/// `ToSocketAddrs` as a trait bound on its parameter in order to accept +/// different types: +/// +/// ```no_run +/// use std::net::{TcpStream, Ipv4Addr}; +/// +/// let stream = TcpStream::connect(("127.0.0.1", 443)); +/// // or +/// let stream = TcpStream::connect("127.0.0.1:443"); +/// // or +/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443)); +/// ``` +/// +/// [`TcpStream::connect`]: ../../std/net/struct.TcpStream.html#method.connect +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ToSocketAddrs { + /// Returned iterator over socket addresses which this type may correspond + /// to. + #[stable(feature = "rust1", since = "1.0.0")] + type Iter: Iterator<Item=SocketAddr>; + + /// 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. + #[stable(feature = "rust1", since = "1.0.0")] + fn to_socket_addrs(&self) -> io::Result<Self::Iter>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddr { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + Ok(Some(*self).into_iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddrV4 { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + SocketAddr::V4(*self).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddrV6 { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + SocketAddr::V6(*self).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (IpAddr, u16) { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + let (ip, port) = *self; + match ip { + IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), + IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (Ipv4Addr, u16) { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + let (ip, port) = *self; + SocketAddrV4::new(ip, port).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (Ipv6Addr, u16) { + type Iter = option::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> { + let (ip, port) = *self; + SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs() + } +} + +fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> { + let ips = lookup_host(s)?; + let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); + Ok(v.into_iter()) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> ToSocketAddrs for (&'a str, u16) { + type Iter = vec::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> { + let (host, port) = *self; + + // try to parse the host as a regular IP address first + if let Ok(addr) = host.parse::<Ipv4Addr>() { + let addr = SocketAddrV4::new(addr, port); + return Ok(vec![SocketAddr::V4(addr)].into_iter()) + } + if let Ok(addr) = host.parse::<Ipv6Addr>() { + let addr = SocketAddrV6::new(addr, port, 0, 0); + return Ok(vec![SocketAddr::V6(addr)].into_iter()) + } + + resolve_socket_addr(host, port) + } +} + +// accepts strings like 'localhost:12345' +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for str { + type Iter = vec::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> { + // try to parse as a regular SocketAddr first + if let Some(addr) = self.parse().ok() { + return Ok(vec![addr].into_iter()); + } + + macro_rules! try_opt { + ($e:expr, $msg:expr) => ( + match $e { + Some(r) => r, + None => return Err(io::Error::new(io::ErrorKind::InvalidInput, + $msg)), + } + ) + } + + // split the string by ':' and convert the second part to u16 + let mut parts_iter = self.rsplitn(2, ':'); + let port_str = try_opt!(parts_iter.next(), "invalid socket address"); + let host = try_opt!(parts_iter.next(), "invalid socket address"); + let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); + resolve_socket_addr(host, port) + } +} + +#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")] +impl<'a> ToSocketAddrs for &'a [SocketAddr] { + type Iter = iter::Cloned<slice::Iter<'a, SocketAddr>>; + + fn to_socket_addrs(&self) -> io::Result<Self::Iter> { + Ok(self.iter().cloned()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { + type Iter = T::Iter; + fn to_socket_addrs(&self) -> io::Result<T::Iter> { + (**self).to_socket_addrs() + } +} + +#[stable(feature = "string_to_socket_addrs", since = "1.16.0")] +impl ToSocketAddrs for String { + type Iter = vec::IntoIter<SocketAddr>; + fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> { + (&**self).to_socket_addrs() + } +} + +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests { + use net::*; + use net::test::{tsa, sa6, sa4}; + + #[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 to_socket_addr_str_u16() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); + } + + #[test] + fn to_socket_addr_str() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + assert!(tsa("localhost:23924").unwrap().contains(&a)); + } + + #[test] + fn to_socket_addr_string() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); + + let s = format!("{}:{}", "77.88.21.11", "24352"); + assert_eq!(Ok(vec![a]), tsa(s)); + // s has been moved into the tsa call + } + + // FIXME: figure out why this fails on openbsd and bitrig and fix it + #[test] + #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))] + fn to_socket_addr_str_bad() { + assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); + } + + #[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()); + } +} diff --git a/ctr-std/src/net/ip.rs b/ctr-std/src/net/ip.rs new file mode 100644 index 0000000..0d73a6f --- /dev/null +++ b/ctr-std/src/net/ip.rs @@ -0,0 +1,1835 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "ip", reason = "extra functionality has not been \ + scrutinized to the level that it should \ + be to be stable", + issue = "27709")] + +use cmp::Ordering; +use fmt; +use hash; +use mem; +use net::{hton, ntoh}; +use sys::net::netc as c; +use sys_common::{AsInner, FromInner}; + +/// An IP address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// +/// # Examples +/// +/// ``` +/// use 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); +/// ``` +#[stable(feature = "ip_addr", since = "1.7.0")] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// An IPv4 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), + /// An IPv6 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V6(#[stable(feature = "ip_addr", since = "1.7.0")] 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 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// +/// # Examples +/// +/// ``` +/// use 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)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv4Addr { + inner: c::in_addr, +} + +/// 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 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # 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`]: ../../std/str/trait.FromStr.html +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use 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)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv6Addr { + inner: c::in6_addr, +} + +#[allow(missing_docs)] +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +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`][IPv4] and + /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_unspecified(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_unspecified(), + IpAddr::V6(ref a) => a.is_unspecified(), + } + } + + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and + /// [`Ipv6Addr::is_loopback`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_loopback(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_loopback(), + IpAddr::V6(ref a) => a.is_loopback(), + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and + /// [`Ipv6Addr::is_global`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub fn is_global(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_global(), + IpAddr::V6(ref a) => a.is_global(), + } + } + + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and + /// [`Ipv6Addr::is_multicast`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_multicast(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_multicast(), + IpAddr::V6(ref a) => a.is_multicast(), + } + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and + /// [`Ipv6Addr::is_documentation`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub fn is_documentation(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_documentation(), + IpAddr::V6(ref a) => a.is_documentation(), + } + } + + /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + pub fn is_ipv4(&self) -> bool { + match *self { + IpAddr::V4(_) => true, + IpAddr::V6(_) => false, + } + } + + /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv6 address]: #variant.V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + pub fn is_ipv6(&self) -> bool { + match *self { + IpAddr::V4(_) => false, + IpAddr::V6(_) => true, + } + } +} + +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 std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + inner: c::in_addr { + s_addr: hton(((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + (d as u32)), + } + } + } + + /// Creates a new IPv4 address with the address pointing to localhost: 127.0.0.1. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::localhost(); + /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub fn localhost() -> Ipv4Addr { + Ipv4Addr::new(127, 0, 0, 1) + } + + /// Creates a new IPv4 address representing an unspecified address: 0.0.0.0 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::unspecified(); + /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub fn unspecified() -> Ipv4Addr { + Ipv4Addr::new(0, 0, 0, 0) + } + + /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn octets(&self) -> [u8; 4] { + let bits = ntoh(self.inner.s_addr); + [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] + } + + /// 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_unspecified(&self) -> bool { + self.inner.s_addr == 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_private(&self) -> bool { + match (self.octets()[0], self.octets()[1]) { + (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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_link_local(&self) -> bool { + self.octets()[0] == 169 && self.octets()[1] == 254 + } + + /// Returns [`true`] if the address appears to be globally routable. + /// See [iana-ipv4-special-registry][ipv4-sr]. + /// + /// The following return false: + /// + /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) + /// - the loopback address (127.0.0.0/8) + /// - the link-local address (169.254.0.0/16) + /// - the broadcast address (255.255.255.255/32) + /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) + /// - the unspecified address (0.0.0.0) + /// + /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// 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); + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// } + /// ``` + pub fn is_global(&self) -> bool { + !self.is_private() && !self.is_loopback() && !self.is_link_local() && + !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() + } + + /// 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_broadcast(&self) -> bool { + self.octets()[0] == 255 && self.octets()[1] == 255 && + self.octets()[2] == 255 && self.octets()[3] == 255 + } + + /// 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_documentation(&self) -> bool { + match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { + (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 + /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0, + ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, + ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) + } + + /// Converts this address to an IPv4-mapped [IPv6 address]. + /// + /// a.b.c.d becomes ::ffff:a.b.c.d + /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, + ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, + ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) + } +} + +#[stable(feature = "ip_addr", since = "1.7.0")] +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpAddr::V4(ref a) => a.fmt(fmt), + IpAddr::V6(ref a) => a.fmt(fmt), + } + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<Ipv4Addr> for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<Ipv6Addr> for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let octets = self.octets(); + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { *self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq<Ipv4Addr> for IpAddr { + fn eq(&self, other: &Ipv4Addr) -> bool { + match *self { + IpAddr::V4(ref v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq<IpAddr> for Ipv4Addr { + fn eq(&self, other: &IpAddr) -> bool { + match *other { + IpAddr::V4(ref v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Ipv4Addr {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv4Addr { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + // `inner` is #[repr(packed)], so we need to copy `s_addr`. + {self.inner.s_addr}.hash(s) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd<Ipv4Addr> for IpAddr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { + match *self { + IpAddr::V4(ref v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd<IpAddr> for Ipv4Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { + match *other { + IpAddr::V4(ref v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + ntoh(self.inner.s_addr).cmp(&ntoh(other.inner.s_addr)) + } +} + +impl AsInner<c::in_addr> for Ipv4Addr { + fn as_inner(&self) -> &c::in_addr { &self.inner } +} +impl FromInner<c::in_addr> for Ipv4Addr { + fn from_inner(addr: c::in_addr) -> Ipv4Addr { + Ipv4Addr { inner: addr } + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From<Ipv4Addr> for u32 { + /// It performs the conversion in network order (big-endian). + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From<u32> for Ipv4Addr { + /// It performs the conversion in network order (big-endian). + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) + } +} + +#[stable(feature = "from_slice_v4", since = "1.9.0")] +impl From<[u8; 4]> for Ipv4Addr { + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 4]> for IpAddr { + 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 std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, + h: u16) -> Ipv6Addr { + let mut addr: c::in6_addr = unsafe { mem::zeroed() }; + addr.s6_addr = [(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]; + Ipv6Addr { inner: addr } + } + + /// Creates a new IPv6 address representing localhost: `::1`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::localhost(); + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub fn localhost() -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1) + } + + /// Creates a new IPv6 address representing the unspecified address: `::` + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::unspecified(); + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub fn unspecified() -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) + } + + /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn segments(&self) -> [u16; 8] { + let arr = &self.inner.s6_addr; + [ + (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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_unspecified(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + } + + /// 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_loopback(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// The following return [`false`]: + /// + /// - the loopback address + /// - link-local, site-local, and unique local unicast addresses + /// - interface-, link-, realm-, admin- and site-local multicast addresses + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns [`true`] if the address is unicast and link-local (fe80::/10). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// } + /// ``` + pub 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). + /// + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub 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 + /// - the (deprecated) site-local addresses + /// - unique local addresses + /// - the unspecified address + /// - the address range reserved for documentation + /// + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub fn is_unicast_global(&self) -> bool { + !self.is_multicast() + && !self.is_loopback() && !self.is_unicast_link_local() + && !self.is_unicast_site_local() && !self.is_unique_local() + && !self.is_unspecified() && !self.is_documentation() + } + + /// Returns the address's multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// fn main() { + /// 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); + /// } + /// ``` + pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { + 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 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use 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); + /// ``` + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// 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]: ../../std/net/struct.Ipv4Addr.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use 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))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv4(&self) -> Option<Ipv4Addr> { + match self.segments() { + [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { + Some(Ipv4Addr::new((g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8)) + }, + _ => None + } + } + + /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use 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]); + /// ``` + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] + pub fn octets(&self) -> [u8; 16] { + self.inner.s6_addr + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.segments() { + // We need special cases for :: and ::1, otherwise they're formatted + // as ::0.0.0.[01] + [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"), + [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"), + // Ipv4 Compatible address + [0, 0, 0, 0, 0, 0, g, h] => { + write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8) + } + // Ipv4-Mapped address + [0, 0, 0, 0, 0, 0xffff, g, h] => { + write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8) + }, + _ => { + fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { + let mut longest_span_len = 0; + let mut longest_span_at = 0; + let mut cur_span_len = 0; + let mut cur_span_at = 0; + + for i in 0..8 { + if segments[i] == 0 { + if cur_span_len == 0 { + cur_span_at = i; + } + + cur_span_len += 1; + + if cur_span_len > longest_span_len { + longest_span_len = cur_span_len; + longest_span_at = cur_span_at; + } + } else { + cur_span_len = 0; + cur_span_at = 0; + } + } + + (longest_span_at, longest_span_len) + } + + let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); + + if zeros_len > 1 { + fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter) -> fmt::Result { + if !segments.is_empty() { + write!(fmt, "{:x}", segments[0])?; + for &seg in &segments[1..] { + write!(fmt, ":{:x}", seg)?; + } + } + Ok(()) + } + + fmt_subslice(&self.segments()[..zeros_at], fmt)?; + fmt.write_str("::")?; + fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt) + } else { + let &[a, b, c, d, e, f, g, h] = &self.segments(); + write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + a, b, c, d, e, f, g, h) + } + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { *self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq<IpAddr> for Ipv6Addr { + fn eq(&self, other: &IpAddr) -> bool { + match *other { + IpAddr::V4(_) => false, + IpAddr::V6(ref v6) => self == v6, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq<Ipv6Addr> for IpAddr { + fn eq(&self, other: &Ipv6Addr) -> bool { + match *self { + IpAddr::V4(_) => false, + IpAddr::V6(ref v6) => v6 == other, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Ipv6Addr {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv6Addr { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + self.inner.s6_addr.hash(s) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd<Ipv6Addr> for IpAddr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { + match *self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(ref v6) => v6.partial_cmp(other), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd<IpAddr> for Ipv6Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { + match *other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(ref v6) => self.partial_cmp(v6), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} + +impl AsInner<c::in6_addr> for Ipv6Addr { + fn as_inner(&self) -> &c::in6_addr { &self.inner } +} +impl FromInner<c::in6_addr> for Ipv6Addr { + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr { inner: addr } + } +} + +#[unstable(feature = "i128", issue = "35118")] +impl From<Ipv6Addr> for u128 { + fn from(ip: Ipv6Addr) -> u128 { + let ip = ip.segments(); + ((ip[0] as u128) << 112) + ((ip[1] as u128) << 96) + ((ip[2] as u128) << 80) + + ((ip[3] as u128) << 64) + ((ip[4] as u128) << 48) + ((ip[5] as u128) << 32) + + ((ip[6] as u128) << 16) + (ip[7] as u128) + } +} +#[unstable(feature = "i128", issue = "35118")] +impl From<u128> for Ipv6Addr { + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::new( + (ip >> 112) as u16, (ip >> 96) as u16, (ip >> 80) as u16, + (ip >> 64) as u16, (ip >> 48) as u16, (ip >> 32) as u16, + (ip >> 16) as u16, ip as u16, + ) + } +} + +#[stable(feature = "ipv6_from_octets", since = "1.9.0")] +impl From<[u8; 16]> for Ipv6Addr { + fn from(octets: [u8; 16]) -> Ipv6Addr { + let mut inner: c::in6_addr = unsafe { mem::zeroed() }; + inner.s6_addr = octets; + Ipv6Addr::from_inner(inner) + } +} + +#[stable(feature = "ipv6_from_segments", since = "1.16.0")] +impl From<[u16; 8]> for Ipv6Addr { + 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) + } +} + + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 16]> for IpAddr { + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u16; 8]> for IpAddr { + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} + +// Tests for this module +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests { + use net::*; + use net::Ipv6MulticastScope::*; + use net::test::{tsa, sa6, sa4}; + + #[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<Ipv4Addr> = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option<Ipv4Addr> = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option<Ipv4Addr> = "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<Ipv6Addr> = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option<Ipv6Addr> = "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<Ipv4Addr> = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option<Ipv6Addr> = "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<SocketAddr> = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option<SocketAddr> = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); + } + + #[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"); + + // 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()); + } + + #[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()); + } + + #[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() { + fn check4(octets: &[u8; 4], unspec: bool, loopback: bool, + global: bool, multicast: bool, documentation: bool) { + let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_documentation(), documentation); + } + + fn check6(str_addr: &str, unspec: bool, loopback: bool, + global: bool, u_doc: bool, mcast: bool) { + let ip = IpAddr::V6(str_addr.parse().unwrap()); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_documentation(), u_doc); + assert_eq!(ip.is_multicast(), mcast); + } + + // address unspec loopbk global multicast doc + check4(&[0, 0, 0, 0], true, false, false, false, false); + check4(&[0, 0, 0, 1], false, false, true, false, false); + check4(&[0, 1, 0, 0], false, false, true, false, false); + check4(&[10, 9, 8, 7], false, false, false, false, false); + check4(&[127, 1, 2, 3], false, true, false, false, false); + check4(&[172, 31, 254, 253], false, false, false, false, false); + check4(&[169, 254, 253, 242], false, false, false, false, false); + check4(&[192, 0, 2, 183], false, false, false, false, true); + check4(&[192, 1, 2, 183], false, false, true, false, false); + check4(&[192, 168, 254, 253], false, false, false, false, false); + check4(&[198, 51, 100, 0], false, false, false, false, true); + check4(&[203, 0, 113, 0], false, false, false, false, true); + check4(&[203, 2, 113, 0], false, false, true, false, false); + check4(&[224, 0, 0, 0], false, false, true, true, false); + check4(&[239, 255, 255, 255], false, false, true, true, false); + check4(&[255, 255, 255, 255], false, false, false, false, false); + + // address unspec loopbk global doc mcast + check6("::", true, false, false, false, false); + check6("::1", false, true, false, false, false); + check6("::0.0.0.2", false, false, true, false, false); + check6("1::", false, false, true, false, false); + check6("fc00::", false, false, false, false, false); + check6("fdff:ffff::", false, false, false, false, false); + check6("fe80:ffff::", false, false, false, false, false); + check6("febf:ffff::", false, false, false, false, false); + check6("fec0::", false, false, false, false, false); + check6("ff01::", false, false, false, false, true); + check6("ff02::", false, false, false, false, true); + check6("ff03::", false, false, false, false, true); + check6("ff04::", false, false, false, false, true); + check6("ff05::", false, false, false, false, true); + check6("ff08::", false, false, false, false, true); + check6("ff0e::", false, false, true, false, true); + check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false); + check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false); + } + + #[test] + fn ipv4_properties() { + fn check(octets: &[u8; 4], unspec: bool, loopback: bool, + private: bool, link_local: bool, global: bool, + multicast: bool, broadcast: bool, documentation: bool) { + let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); + assert_eq!(octets, &ip.octets()); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_private(), private); + assert_eq!(ip.is_link_local(), link_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_broadcast(), broadcast); + assert_eq!(ip.is_documentation(), documentation); + } + + // address unspec loopbk privt linloc global multicast brdcast doc + check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false); + check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); + check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false); + check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); + check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); + check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); + check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); + check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); + check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); + check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); + check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); + check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); + } + + #[test] + fn ipv6_properties() { + fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool, + unique_local: bool, global: bool, + u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool, + m_scope: Option<Ipv6MulticastScope>) { + let ip: Ipv6Addr = str_addr.parse().unwrap(); + assert_eq!(str_addr, ip.to_string()); + assert_eq!(&ip.octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_unique_local(), unique_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_unicast_link_local(), u_link_local); + assert_eq!(ip.is_unicast_site_local(), u_site_local); + assert_eq!(ip.is_unicast_global(), u_global); + assert_eq!(ip.is_documentation(), u_doc); + assert_eq!(ip.multicast_scope(), m_scope); + assert_eq!(ip.is_multicast(), m_scope.is_some()); + } + + // unspec loopbk uniqlo global unill unisl uniglo doc mscope + check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + true, false, false, false, false, false, false, false, None); + check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + false, true, false, false, false, false, false, false, None); + check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + false, false, false, true, false, false, true, false, None); + check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, true, false, false, true, false, None); + check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, true, false, false, false, false, false, None); + check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, true, false, false, false, false, false, None); + check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, true, false, false, false, None); + check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, true, false, false, false, None); + check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, true, false, false, None); + check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(InterfaceLocal)); + check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(LinkLocal)); + check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(RealmLocal)); + check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(AdminLocal)); + check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(SiteLocal)); + check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, false, false, false, false, false, Some(OrganizationLocal)); + check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + false, false, false, true, false, false, false, false, Some(Global)); + check("2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + false, false, false, false, false, false, false, true, None); + 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], + false, false, false, true, false, false, true, false, None); + } + + #[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()); + } + + #[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::<Ipv6Addr>().unwrap(); + let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().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()); + } +} diff --git a/ctr-std/src/net/mod.rs b/ctr-std/src/net/mod.rs new file mode 100644 index 0000000..9fcb93e --- /dev/null +++ b/ctr-std/src/net/mod.rs @@ -0,0 +1,186 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 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. +//! +//! # Organization +//! +//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP +//! * [`UdpSocket`] provides functionality for communication over UDP +//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and +//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses +//! * [`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 +//! +//! [`IpAddr`]: ../../std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +//! [`TcpListener`]: ../../std/net/struct.TcpListener.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html +//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use fmt; +use io::{self, Error, ErrorKind}; +use sys_common::net as net_imp; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::tcp::{TcpStream, TcpListener, Incoming}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::udp::UdpSocket; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::parser::AddrParseError; + +mod ip; +mod addr; +mod tcp; +mod udp; +mod parser; +#[cfg(test)] +mod test; + +/// Possible values which can be passed to the [`shutdown`] method of +/// [`TcpStream`]. +/// +/// [`shutdown`]: struct.TcpStream.html#method.shutdown +/// [`TcpStream`]: struct.TcpStream.html +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Shutdown { + /// The reading portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [reads] will return [`Ok(0)`]. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [reads]: ../../std/io/trait.Read.html + /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok + #[stable(feature = "rust1", since = "1.0.0")] + Read, + /// The writing portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [writes] will return an error. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [writes]: ../../std/io/trait.Write.html + #[stable(feature = "rust1", since = "1.0.0")] + Write, + /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. + /// + /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [`Shutdown::Read`]: #variant.Read + /// [`Shutdown::Write`]: #variant.Write + #[stable(feature = "rust1", since = "1.0.0")] + Both, +} + +#[doc(hidden)] +trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +fn hton<I: NetInt>(i: I) -> I { i.to_be() } +fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) } + +fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> + where F: FnMut(&SocketAddr) -> io::Result<T> +{ + let mut last_err = None; + for addr in addr.to_socket_addrs()? { + match f(&addr) { + Ok(l) => return Ok(l), + Err(e) => last_err = Some(e), + } + } + Err(last_err.unwrap_or_else(|| { + Error::new(ErrorKind::InvalidInput, + "could not resolve to any addresses") + })) +} + +/// An iterator over `SocketAddr` values returned from a host lookup operation. +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses", + issue = "27705")] +pub struct LookupHost(net_imp::LookupHost); + +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses", + issue = "27705")] +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option<SocketAddr> { self.0.next() } +} + +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses", + issue = "27705")] +impl fmt::Debug for LookupHost { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("LookupHost { .. }") + } +} + +/// Resolve the host specified by `host` as a number of `SocketAddr` instances. +/// +/// This method may perform a DNS query to resolve `host` and may also inspect +/// system configuration to resolve the specified hostname. +/// +/// The returned iterator will skip over any unknown addresses returned by the +/// operating system. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(lookup_host)] +/// +/// use std::net; +/// +/// # fn foo() -> std::io::Result<()> { +/// for host in net::lookup_host("rust-lang.org")? { +/// println!("found address: {}", host); +/// } +/// # Ok(()) +/// # } +/// ``` +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses", + issue = "27705")] +pub fn lookup_host(host: &str) -> io::Result<LookupHost> { + net_imp::lookup_host(host).map(LookupHost) +} diff --git a/ctr-std/src/net/parser.rs b/ctr-std/src/net/parser.rs new file mode 100644 index 0000000..261d44e --- /dev/null +++ b/ctr-std/src/net/parser.rs @@ -0,0 +1,398 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A private parser implementation of IPv4, IPv6, and socket addresses. +//! +//! This module is "publicly exported" through the `FromStr` implementations +//! below. + +use error::Error; +use fmt; +use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use str::FromStr; + +struct Parser<'a> { + // parsing as ASCII, so can use byte array + s: &'a [u8], + pos: usize, +} + +impl<'a> Parser<'a> { + fn new(s: &'a str) -> Parser<'a> { + Parser { + s: s.as_bytes(), + pos: 0, + } + } + + fn is_eof(&self) -> bool { + self.pos == self.s.len() + } + + // Commit only if parser returns Some + fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where + F: FnOnce(&mut Parser) -> Option<T>, + { + let pos = self.pos; + let r = cb(self); + if r.is_none() { + self.pos = pos; + } + r + } + + // Commit only if parser read till EOF + fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where + F: FnOnce(&mut Parser) -> Option<T>, + { + self.read_atomically(move |p| { + match cb(p) { + Some(x) => if p.is_eof() {Some(x)} else {None}, + None => None, + } + }) + } + + // Return result of first successful parser + fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>]) + -> Option<T> { + for pf in parsers { + if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { + return Some(r); + } + } + None + } + + // Apply 3 parsers sequentially + fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, + pa: PA, + pb: PB, + pc: PC) + -> Option<(A, B, C)> where + PA: FnOnce(&mut Parser) -> Option<A>, + PB: FnOnce(&mut Parser) -> Option<B>, + PC: FnOnce(&mut Parser) -> Option<C>, + { + self.read_atomically(move |p| { + let a = pa(p); + let b = if a.is_some() { pb(p) } else { None }; + let c = if b.is_some() { pc(p) } else { None }; + match (a, b, c) { + (Some(a), Some(b), Some(c)) => Some((a, b, c)), + _ => None + } + }) + } + + // Read next char + fn read_char(&mut self) -> Option<char> { + if self.is_eof() { + None + } else { + let r = self.s[self.pos] as char; + self.pos += 1; + Some(r) + } + } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option<char> { + self.read_atomically(|p| { + match p.read_char() { + Some(next) if next == c => Some(next), + _ => None, + } + }) + } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option<u8> { + fn parse_digit(c: char, radix: u8) -> Option<u8> { + let c = c as u8; + // assuming radix is either 10 or 16 + if c >= b'0' && c <= b'9' { + Some(c - b'0') + } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { + Some(c - b'a' + 10) + } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { + Some(c - b'A' + 10) + } else { + None + } + } + + self.read_atomically(|p| { + p.read_char().and_then(|c| parse_digit(c, radix)) + }) + } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + let mut r = 0; + let mut digit_count = 0; + loop { + match self.read_digit(radix) { + Some(d) => { + r = r * (radix as u32) + (d as u32); + digit_count += 1; + if digit_count > max_digits || r >= upto { + return None + } + } + None => { + if digit_count == 0 { + return None + } else { + return Some(r) + } + } + }; + } + } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) + } + + fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> { + let mut bs = [0; 4]; + let mut i = 0; + while i < 4 { + if i != 0 && self.read_given_char('.').is_none() { + return None; + } + + bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?; + i += 1; + } + Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3])) + } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> { + self.read_atomically(|p| p.read_ipv4_addr_impl()) + } + + fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> { + fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0; 8]; + gs[..head.len()].copy_from_slice(head); + gs[(8 - tail.len()) .. 8].copy_from_slice(tail); + Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) + } + + fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) + -> (usize, bool) { + let mut i = 0; + while i < limit { + if i < limit - 1 { + let ipv4 = p.read_atomically(|p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_ipv4_addr() + } else { + None + } + }); + if let Some(v4_addr) = ipv4 { + let octets = v4_addr.octets(); + groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); + groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16); + return (i + 2, true); + } + } + + let group = p.read_atomically(|p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_number(16, 4, 0x10000).map(|n| n as u16) + } else { + None + } + }); + match group { + Some(g) => groups[i] = g, + None => return (i, false) + } + i += 1; + } + (i, false) + } + + let mut head = [0; 8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr::new( + head[0], head[1], head[2], head[3], + head[4], head[5], head[6], head[7])) + } + + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None + } + + // read `::` if previous code parsed less than 8 groups + if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + return None; + } + + let mut tail = [0; 8]; + // `::` indicates one or more groups of 16 bits of zeros + let limit = 8 - (head_size + 1); + let (tail_size, _) = read_groups(self, &mut tail, limit); + Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) + } + + fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> { + self.read_atomically(|p| p.read_ipv6_addr_impl()) + } + + fn read_ip_addr(&mut self) -> Option<IpAddr> { + let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(IpAddr::V4); + let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(IpAddr::V6); + self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) + } + + fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> { + let ip_addr = |p: &mut Parser| p.read_ipv4_addr(); + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| { + p.read_number(10, 5, 0x10000).map(|n| n as u16) + }; + + self.read_seq_3(ip_addr, colon, port).map(|t| { + let (ip, _, port): (Ipv4Addr, char, u16) = t; + SocketAddrV4::new(ip, port) + }) + } + + fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> { + let ip_addr = |p: &mut Parser| { + let open_br = |p: &mut Parser| p.read_given_char('['); + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser| p.read_given_char(']'); + p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) + }; + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| { + p.read_number(10, 5, 0x10000).map(|n| n as u16) + }; + + self.read_seq_3(ip_addr, colon, port).map(|t| { + let (ip, _, port): (Ipv6Addr, char, u16) = t; + SocketAddrV6::new(ip, port, 0, 0) + }) + } + + fn read_socket_addr(&mut self) -> Option<SocketAddr> { + let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4); + let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6); + self.read_or(&mut [Box::new(v4), Box::new(v6)]) + } +} + +#[stable(feature = "ip_addr", since = "1.7.0")] +impl FromStr for IpAddr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<IpAddr, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for Ipv4Addr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for Ipv6Addr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +#[stable(feature = "socket_addr_from_str", since = "1.5.0")] +impl FromStr for SocketAddrV4 { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())), + } + } +} + +#[stable(feature = "socket_addr_from_str", since = "1.5.0")] +impl FromStr for SocketAddrV6 { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for SocketAddr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())), + } + } +} + +/// 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`]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AddrParseError(()); + +#[stable(feature = "addr_parse_error_error", since = "1.4.0")] +impl fmt::Display for AddrParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.description()) + } +} + +#[stable(feature = "addr_parse_error_error", since = "1.4.0")] +impl Error for AddrParseError { + fn description(&self) -> &str { + "invalid IP address syntax" + } +} diff --git a/ctr-std/src/net/tcp.rs b/ctr-std/src/net/tcp.rs new file mode 100644 index 0000000..78235ea --- /dev/null +++ b/ctr-std/src/net/tcp.rs @@ -0,0 +1,1662 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io::prelude::*; + +use fmt; +use io::{self, Initializer}; +use net::{ToSocketAddrs, SocketAddr, Shutdown}; +use sys_common::net as net_imp; +use sys_common::{AsInner, FromInner, IntoInner}; +use time::Duration; + +/// A TCP stream between a local and a remote socket. +/// +/// After creating a `TcpStream` by either [`connect`]ing to a remote host or +/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted +/// by [reading] and [writing] to it. +/// +/// The connection will be closed when the value is dropped. The reading and writing +/// portions of the connection can also be shut down individually with the [`shutdown`] +/// method. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`connect`]: #method.connect +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [reading]: ../../std/io/trait.Read.html +/// [`shutdown`]: #method.shutdown +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [writing]: ../../std/io/trait.Write.html +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// { +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// // ignore the Result +/// let _ = stream.write(&[1]); +/// let _ = stream.read(&mut [0; 128]); // ignore here too +/// } // the stream is closed here +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct TcpStream(net_imp::TcpStream); + +/// A TCP socket server, listening for connections. +/// +/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens +/// for incoming TCP connections. These can be accepted by calling [`accept`] or by +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. +/// +/// The socket will be closed when the value is dropped. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: #method.accept +/// [`bind`]: #method.bind +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`Incoming`]: ../../std/net/struct.Incoming.html +/// [`TcpListener::incoming`]: #method.incoming +/// +/// # Examples +/// +/// ``` +/// # use std::io; +/// use std::net::{TcpListener, TcpStream}; +/// +/// fn handle_client(stream: TcpStream) { +/// // ... +/// } +/// +/// # fn process() -> io::Result<()> { +/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// +/// // accept connections and process them serially +/// for stream in listener.incoming() { +/// handle_client(stream?); +/// } +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct TcpListener(net_imp::TcpListener); + +/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. +/// +/// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// See its documentation for more. +/// +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct Incoming<'a> { listener: &'a TcpListener } + +impl TcpStream { + /// Opens a TCP connection to a remote host. + /// + /// `addr` is an address of the remote host. Anything which implements + /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait + /// documentation for concrete examples. + /// + /// If `addr` yields multiple addresses, `connect` will be attempted with + /// each of the addresses until a connection is successful. If none of + /// the addresses result in a successful connection, the error returned from + /// the last connection attempt (the last address) is returned. + /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// Open a TCP connection to `127.0.0.1:8080`: + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") { + /// println!("Connected to the server!"); + /// } else { + /// println!("Couldn't connect to server..."); + /// } + /// ``` + /// + /// Open a TCP connection to `127.0.0.1:8080`. If the connection fails, open + /// a TCP connection to `127.0.0.1:8081`: + /// + /// ```no_run + /// use std::net::{SocketAddr, TcpStream}; + /// + /// let addrs = [ + /// SocketAddr::from(([127, 0, 0, 1], 8080)), + /// SocketAddr::from(([127, 0, 0, 1], 8081)), + /// ]; + /// if let Ok(stream) = TcpStream::connect(&addrs[..]) { + /// println!("Connected to the server!"); + /// } else { + /// println!("Couldn't connect to server..."); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { + super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) + } + + /// Opens a TCP connection to a remote host with a timeout. + /// + /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since + /// timeout must be applied to individual addresses. + /// + /// It is an error to pass a zero `Duration` to this function. + /// + /// Unlike other methods on `TcpStream`, this does not correspond to a + /// single system call. It instead calls `connect` in nonblocking mode and + /// then uses an OS-specific mechanism to await the completion of the + /// connection request. + /// + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + #[stable(feature = "tcpstream_connect_timeout", since = "1.21.0")] + pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { + net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream) + } + + /// Returns the socket address of the remote peer of this TCP connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// assert_eq!(stream.peer_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + self.0.peer_addr() + } + + /// Returns the socket address of the local half of this TCP connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{IpAddr, Ipv4Addr, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// assert_eq!(stream.local_addr().unwrap().ip(), + /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn local_addr(&self) -> io::Result<SocketAddr> { + self.0.socket_addr() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O on the specified + /// portions to return immediately with an appropriate value (see the + /// documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../std/net/enum.Shutdown.html + /// + /// # Platform-specific behavior + /// + /// Calling this function multiple times may result in different behavior, + /// depending on the operating system. On Linux, the second call will + /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`. + /// This may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Shutdown, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.shutdown(Shutdown::Both).expect("shutdown call failed"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `TcpStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// let stream_clone = stream.try_clone().expect("clone failed..."); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn try_clone(&self) -> io::Result<TcpStream> { + self.0.duplicate().map(TcpStream) + } + + /// Sets the read timeout to the timeout specified. + /// + /// If the value specified is [`None`], then [`read`] calls will block + /// indefinitely. It is an error to pass the zero `Duration` to this + /// method. + /// + /// # Note + /// + /// Platforms may return a different error code whenever a read times out as + /// a result of setting this option. For example Unix typically returns an + /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.0.set_read_timeout(dur) + } + + /// Sets the write timeout to the timeout specified. + /// + /// If the value specified is [`None`], then [`write`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this + /// method. + /// + /// # Note + /// + /// Platforms may return a different error code whenever a write times out + /// as a result of setting this option. For example Unix typically returns + /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.0.set_write_timeout(dur) + } + + /// Returns the read timeout of this socket. + /// + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. + /// + /// # Note + /// + /// Some platforms do not provide access to the current timeout. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); + /// assert_eq!(stream.read_timeout().unwrap(), None); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.0.read_timeout() + } + + /// Returns the write timeout of this socket. + /// + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. + /// + /// # Note + /// + /// Some platforms do not provide access to the current timeout. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); + /// assert_eq!(stream.write_timeout().unwrap(), None); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.0.write_timeout() + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8000") + /// .expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let len = stream.peek(&mut buf).expect("peek failed"); + /// ``` + #[stable(feature = "peek", since = "1.18.0")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + self.0.peek(buf) + } + + /// Sets the value of the `TCP_NODELAY` option on this socket. + /// + /// If set, this option disables the Nagle algorithm. This means that + /// segments are always sent as soon as possible, even if there is only a + /// small amount of data. When not set, data is buffered until there is a + /// sufficient amount to send out, thereby avoiding the frequent sending of + /// small packets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nodelay(true).expect("set_nodelay call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + self.0.set_nodelay(nodelay) + } + + /// Gets the value of the `TCP_NODELAY` option on this socket. + /// + /// For more information about this option, see [`set_nodelay`][link]. + /// + /// [link]: #method.set_nodelay + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nodelay(true).expect("set_nodelay call failed"); + /// assert_eq!(stream.nodelay().unwrap_or(false), true); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn nodelay(&self) -> io::Result<bool> { + self.0.nodelay() + } + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This value sets the time-to-live field that is used in every packet sent + /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_ttl(100).expect("set_ttl call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + self.0.set_ttl(ttl) + } + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_ttl(100).expect("set_ttl call failed"); + /// assert_eq!(stream.ttl().unwrap_or(0), 100); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn ttl(&self) -> io::Result<u32> { + self.0.ttl() + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.take_error().expect("No error was expected..."); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0.take_error() + } + + /// Moves this TCP stream into or out of nonblocking mode. + /// + /// This will result in `read`, `write`, `recv` and `send` operations + /// becoming nonblocking, i.e. immediately returning from their calls. + /// If the IO operation is successful, `Ok` is returned and no further + /// action is required. If the IO operation could not be completed and needs + /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is + /// returned. + /// + /// On Unix platforms, calling this method corresponds to calling `fcntl` + /// `FIONBIO`. On Windows calling this method corresponds to calling + /// `ioctlsocket` `FIONBIO`. + /// + /// # Examples + /// + /// Reading bytes from a TCP stream in non-blocking mode: + /// + /// ```no_run + /// use std::io::{self, Read}; + /// use std::net::TcpStream; + /// + /// let mut stream = TcpStream::connect("127.0.0.1:7878") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nonblocking(true).expect("set_nonblocking call failed"); + /// + /// # fn wait_for_fd() { unimplemented!() } + /// let mut buf = vec![]; + /// loop { + /// match stream.read_to_end(&mut buf) { + /// Ok(_) => break, + /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + /// // wait until network socket is ready, typically implemented + /// // via platform-specific APIs such as epoll or IOCP + /// wait_for_fd(); + /// } + /// Err(e) => panic!("encountered IO error: {}", e), + /// }; + /// }; + /// println!("bytes: {:?}", buf); + /// ``` + /// + /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for TcpStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for TcpStream { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Read for &'a TcpStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Write for &'a TcpStream { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +impl AsInner<net_imp::TcpStream> for TcpStream { + fn as_inner(&self) -> &net_imp::TcpStream { &self.0 } +} + +impl FromInner<net_imp::TcpStream> for TcpStream { + fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } +} + +impl IntoInner<net_imp::TcpStream> for TcpStream { + fn into_inner(self) -> net_imp::TcpStream { self.0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl TcpListener { + /// Creates a new `TcpListener` which will be bound to the specified + /// address. + /// + /// The returned listener is ready for accepting connections. + /// + /// Binding with a port number of 0 will request that the OS assigns a port + /// to this listener. The port allocated can be queried via the + /// [`local_addr`] method. + /// + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See + /// its documentation for concrete examples. + /// + /// If `addr` yields multiple addresses, `bind` will be attempted with + /// each of the addresses until one succeeds and returns the listener. If + /// none of the addresses succeed in creating a listener, the error returned + /// from the last attempt (the last address) is returned. + /// + /// [`local_addr`]: #method.local_addr + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// Create a TCP listener bound to `127.0.0.1:80`: + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// ``` + /// + /// Create a TCP listener bound to `127.0.0.1:80`. If that fails, create a + /// TCP listener bound to `127.0.0.1:443`: + /// + /// ```no_run + /// use std::net::{SocketAddr, TcpListener}; + /// + /// let addrs = [ + /// SocketAddr::from(([127, 0, 0, 1], 80)), + /// SocketAddr::from(([127, 0, 0, 1], 443)), + /// ]; + /// let listener = TcpListener::bind(&addrs[..]).unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { + super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener}; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// assert_eq!(listener.local_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn local_addr(&self) -> io::Result<SocketAddr> { + self.0.socket_addr() + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned [`TcpListener`] is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// [`TcpListener`]: ../../std/net/struct.TcpListener.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// let listener_clone = listener.try_clone().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn try_clone(&self) -> io::Result<TcpListener> { + self.0.duplicate().map(TcpListener) + } + + /// Accept a new incoming connection from this listener. + /// + /// This function will block the calling thread until a new TCP connection + /// is established. When established, the corresponding [`TcpStream`] and the + /// remote peer's address will be returned. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// match listener.accept() { + /// Ok((_socket, addr)) => println!("new client: {:?}", addr), + /// Err(e) => println!("couldn't get client: {:?}", e), + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + self.0.accept().map(|(a, b)| (TcpStream(a), b)) + } + + /// Returns an iterator over the connections being received on this + /// listener. + /// + /// The returned iterator will never return [`None`] and will also not yield + /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to + /// calling [`accept`] in a loop. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`accept`]: #method.accept + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// println!("new client!"); + /// } + /// Err(e) => { /* connection failed */ } + /// } + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn incoming(&self) -> Incoming { + Incoming { listener: self } + } + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This value sets the time-to-live field that is used in every packet sent + /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_ttl(100).expect("could not set TTL"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + self.0.set_ttl(ttl) + } + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_ttl(100).expect("could not set TTL"); + /// assert_eq!(listener.ttl().unwrap_or(0), 100); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn ttl(&self) -> io::Result<u32> { + self.0.ttl() + } + + #[stable(feature = "net2_mutators", since = "1.9.0")] + #[rustc_deprecated(since = "1.16.0", + reason = "this option can only be set before the socket is bound")] + #[allow(missing_docs)] + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + self.0.set_only_v6(only_v6) + } + + #[stable(feature = "net2_mutators", since = "1.9.0")] + #[rustc_deprecated(since = "1.16.0", + reason = "this option can only be set before the socket is bound")] + #[allow(missing_docs)] + pub fn only_v6(&self) -> io::Result<bool> { + self.0.only_v6() + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.take_error().expect("No error was expected"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0.take_error() + } + + /// Moves this TCP stream into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e. immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// On Unix platforms, calling this method corresponds to calling `fcntl` + /// `FIONBIO`. On Windows calling this method corresponds to calling + /// `ioctlsocket` `FIONBIO`. + /// + /// # Examples + /// + /// Bind a TCP listener to an address, listen for connections, and read + /// bytes in nonblocking mode: + /// + /// ```no_run + /// use std::io; + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + /// listener.set_nonblocking(true).expect("Cannot set non-blocking"); + /// + /// # fn wait_for_fd() { unimplemented!() } + /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() } + /// for stream in listener.incoming() { + /// match stream { + /// Ok(s) => { + /// // do something with the TcpStream + /// handle_connection(s); + /// } + /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + /// // wait until network socket is ready, typically implemented + /// // via platform-specific APIs such as epoll or IOCP + /// wait_for_fd(); + /// continue; + /// } + /// Err(e) => panic!("encountered IO error: {}", e), + /// } + /// } + /// ``` + /// + /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result<TcpStream>; + fn next(&mut self) -> Option<io::Result<TcpStream>> { + Some(self.listener.accept().map(|p| p.0)) + } +} + +impl AsInner<net_imp::TcpListener> for TcpListener { + fn as_inner(&self) -> &net_imp::TcpListener { &self.0 } +} + +impl FromInner<net_imp::TcpListener> for TcpListener { + fn from_inner(inner: net_imp::TcpListener) -> TcpListener { + TcpListener(inner) + } +} + +impl IntoInner<net_imp::TcpListener> for TcpListener { + fn into_inner(self) -> net_imp::TcpListener { self.0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +mod tests { + use io::ErrorKind; + use io::prelude::*; + use net::*; + use net::test::{next_test_ip4, next_test_ip6}; + use sync::mpsc::channel; + use sys_common::AsInner; + use time::{Instant, Duration}; + use thread; + + fn each_ip(f: &mut FnMut(SocketAddr)) { + f(next_test_ip4()); + f(next_test_ip6()); + } + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + + #[test] + fn bind_error() { + match TcpListener::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => + assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), + } + } + + #[test] + fn connect_error() { + match TcpStream::connect("0.0.0.0:1") { + Ok(..) => panic!(), + Err(e) => assert!(e.kind() == ErrorKind::ConnectionRefused || + e.kind() == ErrorKind::InvalidInput || + e.kind() == ErrorKind::AddrInUse || + e.kind() == ErrorKind::AddrNotAvailable, + "bad error: {} {:?}", e, e.kind()), + } + } + + #[test] + fn listen_localhost() { + let socket_addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&socket_addr)); + + let _t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&("localhost", + socket_addr.port()))); + t!(stream.write(&[144])); + }); + + let mut stream = t!(listener.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 144); + } + + #[test] + fn connect_loopback() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + let host = match addr { + SocketAddr::V4(..) => "127.0.0.1", + SocketAddr::V6(..) => "::1", + }; + let mut stream = t!(TcpStream::connect(&(host, addr.port()))); + t!(stream.write(&[66])); + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 66); + }) + } + + #[test] + fn smoke_test() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + tx.send(t!(stream.local_addr())).unwrap(); + }); + + let (mut stream, addr) = t!(acceptor.accept()); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + assert_eq!(addr, t!(rx.recv())); + }) + } + + #[test] + fn read_eof() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + let _stream = t!(TcpStream::connect(&addr)); + // Close + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + }) + } + + #[test] + fn write_close() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move|| { + drop(t!(TcpStream::connect(&addr))); + tx.send(()).unwrap(); + }); + + let mut stream = t!(acceptor.accept()).0; + rx.recv().unwrap(); + let buf = [0]; + match stream.write(&buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind() == ErrorKind::ConnectionReset || + e.kind() == ErrorKind::BrokenPipe || + e.kind() == ErrorKind::ConnectionAborted, + "unknown error: {}", e); + } + } + }) + } + + #[test] + fn multiple_connect_serial() { + each_ip(&mut |addr| { + let max = 10; + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + for _ in 0..max { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + } + }); + + for stream in acceptor.incoming().take(max) { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert_eq!(buf[0], 99); + } + }) + } + + #[test] + fn multiple_connect_interleaved_greedy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + let acceptor = acceptor; + for (i, stream) in acceptor.incoming().enumerate().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move|| { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == i as u8); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { return } + + let t = thread::spawn(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + // Connect again before writing + connect(i + 1, addr); + t!(stream.write(&[i as u8])); + }); + t.join().ok().unwrap(); + } + } + + #[test] + fn multiple_connect_interleaved_lazy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + for stream in acceptor.incoming().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move|| { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { return } + + let t = thread::spawn(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + connect(i + 1, addr); + t!(stream.write(&[99])); + }); + t.join().ok().unwrap(); + } + } + + #[test] + fn socket_and_peer_name() { + each_ip(&mut |addr| { + let listener = t!(TcpListener::bind(&addr)); + let so_name = t!(listener.local_addr()); + assert_eq!(addr, so_name); + let _t = thread::spawn(move|| { + t!(listener.accept()); + }); + + let stream = t!(TcpStream::connect(&addr)); + assert_eq!(addr, t!(stream.peer_addr())); + }) + } + + #[test] + fn partial_read() { + each_ip(&mut |addr| { + let (tx, rx) = channel(); + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move|| { + let mut cl = t!(srv.accept()).0; + cl.write(&[10]).unwrap(); + let mut b = [0]; + t!(cl.read(&mut b)); + tx.send(()).unwrap(); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + assert_eq!(c.read(&mut b).unwrap(), 1); + t!(c.write(&[1])); + rx.recv().unwrap(); + }) + } + + #[test] + fn double_bind() { + each_ip(&mut |addr| { + let _listener = t!(TcpListener::bind(&addr)); + match TcpListener::bind(&addr) { + Ok(..) => panic!(), + Err(e) => { + assert!(e.kind() == ErrorKind::ConnectionRefused || + e.kind() == ErrorKind::Other || + e.kind() == ErrorKind::AddrInUse, + "unknown error: {} {:?}", e, e.kind()); + } + } + }) + } + + #[test] + fn fast_rebind() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + t!(TcpStream::connect(&addr)); + }); + + t!(acceptor.accept()); + drop(acceptor); + t!(TcpListener::bind(&addr)); + }); + } + + #[test] + fn tcp_clone_smoke() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 0]; + assert_eq!(s.read(&mut buf).unwrap(), 1); + assert_eq!(buf[0], 1); + t!(s.write(&[2])); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move|| { + let mut s2 = s2; + rx1.recv().unwrap(); + t!(s2.write(&[1])); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(s1.read(&mut buf).unwrap(), 1); + rx2.recv().unwrap(); + }) + } + + #[test] + fn tcp_clone_two_read() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move|| { + let mut s = t!(TcpStream::connect(&addr)); + t!(s.write(&[1])); + rx.recv().unwrap(); + t!(s.write(&[2])); + rx.recv().unwrap(); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move|| { + let mut s2 = s2; + let mut buf = [0, 0]; + t!(s2.read(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(s1.read(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) + } + + #[test] + fn tcp_clone_two_write() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move|| { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 1]; + t!(s.read(&mut buf)); + t!(s.read(&mut buf)); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move|| { + let mut s2 = s2; + t!(s2.write(&[1])); + done.send(()).unwrap(); + }); + t!(s1.write(&[2])); + + rx.recv().unwrap(); + }) + } + + #[test] + fn shutdown_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move|| { + let mut c = t!(a.accept()).0; + let mut b = [0]; + assert_eq!(c.read(&mut b).unwrap(), 0); + t!(c.write(&[1])); + }); + + let mut s = t!(TcpStream::connect(&addr)); + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[1]).is_err()); + let mut b = [0, 0]; + assert_eq!(t!(s.read(&mut b)), 1); + assert_eq!(b[0], 1); + }) + } + + #[test] + fn close_readwrite_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx, rx) = channel::<()>(); + let _t = thread::spawn(move|| { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let mut b = [0]; + let mut s = t!(TcpStream::connect(&addr)); + let mut s2 = t!(s.try_clone()); + + // closing should prevent reads/writes + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[0]).is_err()); + t!(s.shutdown(Shutdown::Read)); + assert_eq!(s.read(&mut b).unwrap(), 0); + + // closing should affect previous handles + assert!(s2.write(&[0]).is_err()); + assert_eq!(s2.read(&mut b).unwrap(), 0); + + // closing should affect new handles + let mut s3 = t!(s.try_clone()); + assert!(s3.write(&[0]).is_err()); + assert_eq!(s3.read(&mut b).unwrap(), 0); + + // make sure these don't die + let _ = s2.shutdown(Shutdown::Read); + let _ = s2.shutdown(Shutdown::Write); + let _ = s3.shutdown(Shutdown::Read); + let _ = s3.shutdown(Shutdown::Write); + drop(tx); + }) + } + + #[test] + #[cfg(unix)] // test doesn't work on Windows, see #31657 + fn close_read_wakes_up() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel::<()>(); + let _t = thread::spawn(move|| { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let s = t!(TcpStream::connect(&addr)); + let s2 = t!(s.try_clone()); + let (tx, rx) = channel(); + let _t = thread::spawn(move|| { + let mut s2 = s2; + assert_eq!(t!(s2.read(&mut [0])), 0); + tx.send(()).unwrap(); + }); + // this should wake up the child thread + t!(s.shutdown(Shutdown::Read)); + + // this test will never finish if the child doesn't wake up + rx.recv().unwrap(); + drop(tx1); + }) + } + + #[test] + fn clone_while_reading() { + each_ip(&mut |addr| { + let accept = t!(TcpListener::bind(&addr)); + + // Enqueue a thread to write to a socket + let (tx, rx) = channel(); + let (txdone, rxdone) = channel(); + let txdone2 = txdone.clone(); + let _t = thread::spawn(move|| { + let mut tcp = t!(TcpStream::connect(&addr)); + rx.recv().unwrap(); + t!(tcp.write(&[0])); + txdone2.send(()).unwrap(); + }); + + // Spawn off a reading clone + let tcp = t!(accept.accept()).0; + let tcp2 = t!(tcp.try_clone()); + let txdone3 = txdone.clone(); + let _t = thread::spawn(move|| { + let mut tcp2 = tcp2; + t!(tcp2.read(&mut [0])); + txdone3.send(()).unwrap(); + }); + + // Try to ensure that the reading clone is indeed reading + for _ in 0..50 { + thread::yield_now(); + } + + // clone the handle again while it's reading, then let it finish the + // read. + let _ = t!(tcp.try_clone()); + tx.send(()).unwrap(); + rxdone.recv().unwrap(); + rxdone.recv().unwrap(); + }) + } + + #[test] + fn clone_accept_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let _t = thread::spawn(move|| { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move|| { + let _ = TcpStream::connect(&addr); + }); + + t!(a.accept()); + t!(a2.accept()); + }) + } + + #[test] + fn clone_accept_concurrent() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let (tx, rx) = channel(); + let tx2 = tx.clone(); + + let _t = thread::spawn(move|| { + tx.send(t!(a.accept())).unwrap(); + }); + let _t = thread::spawn(move|| { + tx2.send(t!(a2.accept())).unwrap(); + }); + + let _t = thread::spawn(move|| { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move|| { + let _ = TcpStream::connect(&addr); + }); + + rx.recv().unwrap(); + rx.recv().unwrap(); + }) + } + + #[test] + fn debug() { + let name = if cfg!(windows) {"socket"} else {"fd"}; + let socket_addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&socket_addr)); + let listener_inner = listener.0.socket().as_inner(); + let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}", + socket_addr, name, listener_inner); + assert_eq!(format!("{:?}", listener), compare); + + let stream = t!(TcpStream::connect(&("localhost", + socket_addr.port()))); + let stream_inner = stream.0.socket().as_inner(); + let compare = format!("TcpStream {{ addr: {:?}, \ + peer: {:?}, {}: {:?} }}", + stream.local_addr().unwrap(), + stream.peer_addr().unwrap(), + name, + stream_inner); + assert_eq!(format!("{:?}", stream), compare); + } + + // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // no longer has rounding errors. + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[test] + fn timeouts() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); + drop(listener); + } + + #[test] + fn test_read_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let start = Instant::now(); + let kind = stream.read(&mut buf).err().expect("expected error").kind(); + assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); + } + + #[test] + fn test_read_with_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = t!(listener.accept()).0; + t!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + t!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + let kind = stream.read(&mut buf).err().expect("expected error").kind(); + assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); + } + + #[test] + fn nodelay() { + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + assert_eq!(false, t!(stream.nodelay())); + t!(stream.set_nodelay(true)); + assert_eq!(true, t!(stream.nodelay())); + t!(stream.set_nodelay(false)); + assert_eq!(false, t!(stream.nodelay())); + } + + #[test] + fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_ttl(ttl)); + assert_eq!(ttl, t!(listener.ttl())); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); + } + + #[test] + fn set_nonblocking() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_nonblocking(true)); + t!(listener.set_nonblocking(false)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_nonblocking(false)); + t!(stream.set_nonblocking(true)); + + let mut buf = [0]; + match stream.read(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + } + + #[test] + fn peek() { + each_ip(&mut |addr| { + let (txdone, rxdone) = channel(); + + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move|| { + let mut cl = t!(srv.accept()).0; + cl.write(&[1,3,3,7]).unwrap(); + t!(rxdone.recv()); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + for _ in 1..3 { + let len = c.peek(&mut b).unwrap(); + assert_eq!(len, 4); + } + let len = c.read(&mut b).unwrap(); + assert_eq!(len, 4); + + t!(c.set_nonblocking(true)); + match c.peek(&mut b) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + t!(txdone.send(())); + }) + } + + #[test] + fn connect_timeout_unroutable() { + // this IP is unroutable, so connections should always time out, + // provided the network is reachable to begin with. + let addr = "10.255.255.1:80".parse().unwrap(); + let e = TcpStream::connect_timeout(&addr, Duration::from_millis(250)).unwrap_err(); + assert!(e.kind() == io::ErrorKind::TimedOut || + e.kind() == io::ErrorKind::Other, + "bad error: {} {:?}", e, e.kind()); + } + + #[test] + fn connect_timeout_unbound() { + // bind and drop a socket to track down a "probably unassigned" port + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + drop(socket); + + let timeout = Duration::from_secs(1); + let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err(); + assert!(e.kind() == io::ErrorKind::ConnectionRefused || + e.kind() == io::ErrorKind::TimedOut || + e.kind() == io::ErrorKind::Other, + "bad error: {} {:?}", e, e.kind()); + } + + #[test] + fn connect_timeout_valid() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); + } +} diff --git a/ctr-std/src/net/test.rs b/ctr-std/src/net/test.rs new file mode 100644 index 0000000..aec3d90 --- /dev/null +++ b/ctr-std/src/net/test.rs @@ -0,0 +1,57 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] // not used on emscripten + +use env; +use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; +use sync::atomic::{AtomicUsize, Ordering}; + +static PORT: AtomicUsize = AtomicUsize::new(0); + +pub fn next_test_ip4() -> SocketAddr { + let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) +} + +pub fn next_test_ip6() -> SocketAddr { + let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); + SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), + port, 0, 0)) +} + +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: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> { + match a.to_socket_addrs() { + Ok(a) => Ok(a.collect()), + Err(e) => Err(e.to_string()), + } +} + +// The bots run multiple builds at the same time, and these builds +// all want to use ports. This function figures out which workspace +// it is running in and assigns a port range based on it. +fn base_port() -> u16 { + let cwd = env::current_dir().unwrap(); + let dirs = ["32-opt", "32-nopt", + "musl-64-opt", "cross-opt", + "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", + "all-opt", "snap3", "dist"]; + dirs.iter().enumerate().find(|&(_, dir)| { + cwd.to_str().unwrap().contains(dir) + }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 +} diff --git a/ctr-std/src/net/udp.rs b/ctr-std/src/net/udp.rs new file mode 100644 index 0000000..fc7f920 --- /dev/null +++ b/ctr-std/src/net/udp.rs @@ -0,0 +1,1116 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use io::{self, Error, ErrorKind}; +use net::{ToSocketAddrs, SocketAddr, Ipv4Addr, Ipv6Addr}; +use sys_common::net as net_imp; +use sys_common::{AsInner, FromInner, IntoInner}; +use time::Duration; + +/// A UDP socket. +/// +/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be +/// [sent to] and [received from] any other socket address. +/// +/// Although UDP is a connectionless protocol, this implementation provides an interface +/// to set an address where data should be sent and received from. After setting a remote +/// address with [`connect`], data can be sent to and received from that address with +/// [`send`] and [`recv`]. +/// +/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is +/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP +/// primitives. +/// +/// [`bind`]: #method.bind +/// [`connect`]: #method.connect +/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 +/// [`recv`]: #method.recv +/// [received from]: #method.recv_from +/// [`send`]: #method.send +/// [sent to]: #method.send_to +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// +/// # Examples +/// +/// ```no_run +/// use std::net::UdpSocket; +/// +/// # fn foo() -> std::io::Result<()> { +/// { +/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; +/// +/// // Receives a single datagram message on the socket. If `buf` is too small to hold +/// // the message, it will be cut off. +/// let mut buf = [0; 10]; +/// let (amt, src) = socket.recv_from(&mut buf)?; +/// +/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. +/// let buf = &mut buf[..amt]; +/// buf.reverse(); +/// socket.send_to(buf, &src)?; +/// # Ok(()) +/// } // the socket is closed here +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct UdpSocket(net_imp::UdpSocket); + +impl UdpSocket { + /// Creates a UDP socket from the given address. + /// + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See + /// its documentation for concrete examples. + /// + /// If `addr` yields multiple addresses, `bind` will be attempted with + /// each of the addresses until one succeeds and returns the socket. If none + /// of the addresses succeed in creating a socket, the error returned from + /// the last attempt (the last address) is returned. + /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// Create a UDP socket bound to `127.0.0.1:3400`: + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); + /// ``` + /// + /// Create a UDP socket bound to `127.0.0.1:3400`. If the socket cannot be + /// bound to that address, create a UDP socket bound to `127.0.0.1:3401`: + /// + /// ```no_run + /// use std::net::{SocketAddr, UdpSocket}; + /// + /// let addrs = [ + /// SocketAddr::from(([127, 0, 0, 1], 3400)), + /// SocketAddr::from(([127, 0, 0, 1], 3401)), + /// ]; + /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { + super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) + } + + /// Receives a single datagram message on the socket. On success, returns the number + /// of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf) + /// .expect("Didn't receive data"); + /// let filled_buf = &mut buf[..number_of_bytes]; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0.recv_from(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf) + /// .expect("Didn't receive data"); + /// let filled_buf = &mut buf[..number_of_bytes]; + /// ``` + #[stable(feature = "peek", since = "1.18.0")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0.peek_from(buf) + } + + /// Sends data on the socket to the given address. On success, returns the + /// number of bytes written. + /// + /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its + /// documentation for concrete examples. + /// + /// It is possible for `addr` to yield multiple addresses, but `send_to` + /// will only send data to the first address yielded by `addr`. + /// + /// This will return an error when the IP version of the local socket + /// does not match that returned from [`ToSocketAddrs`]. + /// + /// See <https://github.com/rust-lang/rust/issues/34202> for more details. + /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) + -> io::Result<usize> { + match addr.to_socket_addrs()?.next() { + Some(addr) => self.0.send_to(buf, &addr), + None => Err(Error::new(ErrorKind::InvalidInput, + "no addresses to send data to")), + } + } + + /// Returns the socket address that this socket was created from. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// assert_eq!(socket.local_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn local_addr(&self) -> io::Result<SocketAddr> { + self.0.socket_addr() + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UdpSocket` is a reference to the same socket that this + /// object references. Both handles will read and write the same port, and + /// options set on one socket will be propagated to the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let socket_clone = socket.try_clone().expect("couldn't clone the socket"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn try_clone(&self) -> io::Result<UdpSocket> { + self.0.duplicate().map(UdpSocket) + } + + /// Sets the read timeout to the timeout specified. + /// + /// If the value specified is [`None`], then [`read`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this + /// method. + /// + /// # Note + /// + /// Platforms may return a different error code whenever a read times out as + /// a result of setting this option. For example Unix typically returns an + /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.0.set_read_timeout(dur) + } + + /// Sets the write timeout to the timeout specified. + /// + /// If the value specified is [`None`], then [`write`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this + /// method. + /// + /// # Note + /// + /// Platforms may return a different error code whenever a write times out + /// as a result of setting this option. For example Unix typically returns + /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.0.set_write_timeout(dur) + } + + /// Returns the read timeout of this socket. + /// + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); + /// assert_eq!(socket.read_timeout().unwrap(), None); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.0.read_timeout() + } + + /// Returns the write timeout of this socket. + /// + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); + /// assert_eq!(socket.write_timeout().unwrap(), None); + /// ``` + #[stable(feature = "socket_timeout", since = "1.4.0")] + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.0.write_timeout() + } + + /// Sets the value of the `SO_BROADCAST` option for this socket. + /// + /// When enabled, this socket is allowed to send packets to a broadcast + /// address. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_broadcast(false).expect("set_broadcast call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + self.0.set_broadcast(broadcast) + } + + /// Gets the value of the `SO_BROADCAST` option for this socket. + /// + /// For more information about this option, see + /// [`set_broadcast`][link]. + /// + /// [link]: #method.set_broadcast + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_broadcast(false).expect("set_broadcast call failed"); + /// assert_eq!(socket.broadcast().unwrap(), false); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn broadcast(&self) -> io::Result<bool> { + self.0.broadcast() + } + + /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// If enabled, multicast packets will be looped back to the local socket. + /// Note that this may not have any affect on IPv6 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + self.0.set_multicast_loop_v4(multicast_loop_v4) + } + + /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v4`][link]. + /// + /// [link]: #method.set_multicast_loop_v4 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); + /// assert_eq!(socket.multicast_loop_v4().unwrap(), false); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + self.0.multicast_loop_v4() + } + + /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// Indicates the time-to-live value of outgoing multicast packets for + /// this socket. The default value is 1 which means that multicast packets + /// don't leave the local network unless explicitly requested. + /// + /// Note that this may not have any affect on IPv6 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + self.0.set_multicast_ttl_v4(multicast_ttl_v4) + } + + /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_ttl_v4`][link]. + /// + /// [link]: #method.set_multicast_ttl_v4 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); + /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + self.0.multicast_ttl_v4() + } + + /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// Controls whether this socket sees the multicast packets it sends itself. + /// Note that this may not have any affect on IPv4 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + self.0.set_multicast_loop_v6(multicast_loop_v6) + } + + /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v6`][link]. + /// + /// [link]: #method.set_multicast_loop_v6 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); + /// assert_eq!(socket.multicast_loop_v6().unwrap(), false); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + self.0.multicast_loop_v6() + } + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This value sets the time-to-live field that is used in every packet sent + /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_ttl(42).expect("set_ttl call failed"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + self.0.set_ttl(ttl) + } + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_ttl(42).expect("set_ttl call failed"); + /// assert_eq!(socket.ttl().unwrap(), 42); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn ttl(&self) -> io::Result<u32> { + self.0.ttl() + } + + /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// address of the local interface with which the system should join the + /// multicast group. If it's equal to `INADDR_ANY` then an appropriate + /// interface is chosen by the system. + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + self.0.join_multicast_v4(multiaddr, interface) + } + + /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// index of the interface to join/leave (or 0 to indicate any interface). + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + self.0.join_multicast_v6(multiaddr, interface) + } + + /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v4`][link]. + /// + /// [link]: #method.join_multicast_v4 + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + self.0.leave_multicast_v4(multiaddr, interface) + } + + /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v6`][link]. + /// + /// [link]: #method.join_multicast_v6 + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + self.0.leave_multicast_v6(multiaddr, interface) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// match socket.take_error() { + /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error), + /// Ok(None) => println!("No error"), + /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error), + /// } + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0.take_error() + } + + /// Connects this UDP socket to a remote address, allowing the `send` and + /// `recv` syscalls to be used to send data and also applies filters to only + /// receive data from the specified address. + /// + /// If `addr` yields multiple addresses, `connect` will be attempted with + /// each of the addresses until the underlying OS function returns no + /// error. Note that usually, a successful `connect` call does not specify + /// that there is a remote server listening on the port, rather, such an + /// error would only be detected after the first send. If the OS returns an + /// error for each of the specified addresses, the error returned from the + /// last connection attempt (the last address) is returned. + /// + /// # Examples + /// + /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to + /// `127.0.0.1:8080`: + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); + /// socket.connect("127.0.0.1:8080").expect("connect function failed"); + /// ``` + /// + /// Unlike in the TCP case, passing an array of addresses to the `connect` + /// function of a UDP socket is not a useful thing to do: The OS will be + /// unable to determine whether something is listening on the remote + /// address without the application sending data. + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { + super::each_addr(addr, |addr| self.0.connect(addr)) + } + + /// Sends data on the socket to the remote address to which it is connected. + /// + /// The [`connect`] method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + /// + /// [`connect`]: #method.connect + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.connect("127.0.0.1:8080").expect("connect function failed"); + /// socket.send(&[0, 1, 2]).expect("couldn't send message"); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn send(&self, buf: &[u8]) -> io::Result<usize> { + self.0.send(buf) + } + + /// Receives a single datagram message on the socket from the remote address to + /// which it is connected. On success, returns the number of bytes read. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// The [`connect`] method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + /// + /// [`connect`]: #method.connect + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.connect("127.0.0.1:8080").expect("connect function failed"); + /// let mut buf = [0; 10]; + /// match socket.recv(&mut buf) { + /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]), + /// Err(e) => println!("recv function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + self.0.recv(buf) + } + + /// Receives single datagram on the socket from the remote address to which it is + /// connected, without removing the message from input queue. On success, returns + /// the number of bytes peeked. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// The [`connect`] method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + /// + /// [`connect`]: #method.connect + /// + /// # Errors + /// + /// This method will fail if the socket is not connected. The `connect` method + /// will connect this socket to a remote address. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.connect("127.0.0.1:8080").expect("connect function failed"); + /// let mut buf = [0; 10]; + /// match socket.peek(&mut buf) { + /// Ok(received) => println!("received {} bytes", received), + /// Err(e) => println!("peek function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "peek", since = "1.18.0")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + self.0.peek(buf) + } + + /// Moves this UDP socket into or out of nonblocking mode. + /// + /// This will result in `recv`, `recv_from`, `send`, and `send_to` + /// operations becoming nonblocking, i.e. immediately returning from their + /// calls. If the IO operation is successful, `Ok` is returned and no + /// further action is required. If the IO operation could not be completed + /// and needs to be retried, an error with kind + /// [`io::ErrorKind::WouldBlock`] is returned. + /// + /// On Unix platforms, calling this method corresponds to calling `fcntl` + /// `FIONBIO`. On Windows calling this method corresponds to calling + /// `ioctlsocket` `FIONBIO`. + /// + /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock + /// + /// # Examples + /// + /// Create a UDP socket bound to `127.0.0.1:7878` and read bytes in + /// nonblocking mode: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:7878").unwrap(); + /// socket.set_nonblocking(true).unwrap(); + /// + /// # fn wait_for_fd() { unimplemented!() } + /// let mut buf = [0; 10]; + /// let (num_bytes_read, _) = loop { + /// match socket.recv_from(&mut buf) { + /// Ok(n) => break n, + /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + /// // wait until network socket is ready, typically implemented + /// // via platform-specific APIs such as epoll or IOCP + /// wait_for_fd(); + /// } + /// Err(e) => panic!("encountered IO error: {}", e), + /// } + /// }; + /// println!("bytes: {:?}", &buf[..num_bytes_read]); + /// ``` + #[stable(feature = "net2_mutators", since = "1.9.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } +} + +impl AsInner<net_imp::UdpSocket> for UdpSocket { + fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 } +} + +impl FromInner<net_imp::UdpSocket> for UdpSocket { + fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } +} + +impl IntoInner<net_imp::UdpSocket> for UdpSocket { + fn into_inner(self) -> net_imp::UdpSocket { self.0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for UdpSocket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +mod tests { + use io::ErrorKind; + use net::*; + use net::test::{next_test_ip4, next_test_ip6}; + use sync::mpsc::channel; + use sys_common::AsInner; + use time::{Instant, Duration}; + use thread; + + fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { + f(next_test_ip4(), next_test_ip4()); + f(next_test_ip6(), next_test_ip6()); + } + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + + #[test] + fn bind_error() { + match UdpSocket::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => { + assert_eq!(e.kind(), ErrorKind::AddrNotAvailable) + } + } + } + + #[test] + fn socket_smoke_test_ip4() { + each_ip(&mut |server_ip, client_ip| { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + + let _t = thread::spawn(move|| { + let client = t!(UdpSocket::bind(&client_ip)); + rx1.recv().unwrap(); + t!(client.send_to(&[99], &server_ip)); + tx2.send(()).unwrap(); + }); + + let server = t!(UdpSocket::bind(&server_ip)); + tx1.send(()).unwrap(); + let mut buf = [0]; + let (nread, src) = t!(server.recv_from(&mut buf)); + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + rx2.recv().unwrap(); + }) + } + + #[test] + fn socket_name_ip4() { + each_ip(&mut |addr, _| { + let server = t!(UdpSocket::bind(&addr)); + assert_eq!(addr, t!(server.local_addr())); + }) + } + + #[test] + fn udp_clone_smoke() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let _t = thread::spawn(move|| { + let mut buf = [0, 0]; + assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); + assert_eq!(buf[0], 1); + t!(sock2.send_to(&[2], &addr1)); + }); + + let sock3 = t!(sock1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move|| { + rx1.recv().unwrap(); + t!(sock3.send_to(&[1], &addr2)); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); + rx2.recv().unwrap(); + }) + } + + #[test] + fn udp_clone_two_read() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move|| { + t!(sock2.send_to(&[1], &addr1)); + rx.recv().unwrap(); + t!(sock2.send_to(&[2], &addr1)); + rx.recv().unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move|| { + let mut buf = [0, 0]; + t!(sock3.recv_from(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(sock1.recv_from(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) + } + + #[test] + fn udp_clone_two_write() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let (tx, rx) = channel(); + let (serv_tx, serv_rx) = channel(); + + let _t = thread::spawn(move|| { + let mut buf = [0, 1]; + rx.recv().unwrap(); + t!(sock2.recv_from(&mut buf)); + serv_tx.send(()).unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let tx2 = tx.clone(); + let _t = thread::spawn(move|| { + match sock3.send_to(&[1], &addr2) { + Ok(..) => { let _ = tx2.send(()); } + Err(..) => {} + } + done.send(()).unwrap(); + }); + match sock1.send_to(&[2], &addr2) { + Ok(..) => { let _ = tx.send(()); } + Err(..) => {} + } + drop(tx); + + rx.recv().unwrap(); + serv_rx.recv().unwrap(); + }) + } + + #[test] + fn debug() { + let name = if cfg!(windows) {"socket"} else {"fd"}; + let socket_addr = next_test_ip4(); + + let udpsock = t!(UdpSocket::bind(&socket_addr)); + let udpsock_inner = udpsock.0.socket().as_inner(); + let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", + socket_addr, name, udpsock_inner); + assert_eq!(format!("{:?}", udpsock), compare); + } + + // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code + // no longer has rounding errors. + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[test] + fn timeouts() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); + } + + #[test] + fn test_read_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + + let start = Instant::now(); + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); + assert!(start.elapsed() > Duration::from_millis(400)); + } + + #[test] + fn test_read_with_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + t!(stream.send_to(b"hello world", &addr)); + + let mut buf = [0; 11]; + t!(stream.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); + assert!(start.elapsed() > Duration::from_millis(400)); + } + + #[test] + fn connect_send_recv() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + let mut buf = [0; 11]; + t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + } + + #[test] + fn connect_send_peek_recv() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + for _ in 1..3 { + let mut buf = [0; 11]; + let size = t!(socket.peek(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let size = t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) + } + + #[test] + fn peek_from() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.send_to(b"hello world", &addr)); + + for _ in 1..3 { + let mut buf = [0; 11]; + let (size, _) = t!(socket.peek_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let (size, _) = t!(socket.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) + } + + #[test] + fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); + } + + #[test] + fn set_nonblocking() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + + t!(socket.set_nonblocking(true)); + t!(socket.set_nonblocking(false)); + + t!(socket.connect(addr)); + + t!(socket.set_nonblocking(false)); + t!(socket.set_nonblocking(true)); + + let mut buf = [0]; + match socket.recv(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + }) + } +} |