aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/net
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/net
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadarchived-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.rs1067
-rw-r--r--ctr-std/src/net/ip.rs1835
-rw-r--r--ctr-std/src/net/mod.rs186
-rw-r--r--ctr-std/src/net/parser.rs398
-rw-r--r--ctr-std/src/net/tcp.rs1662
-rw-r--r--ctr-std/src/net/test.rs57
-rw-r--r--ctr-std/src/net/udp.rs1116
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),
+ }
+ })
+ }
+}