about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-03-13 14:22:33 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-03-13 16:47:42 -0700
commitf798674b86382929ca17c88de422a6e2fdb27f2a (patch)
treeeac26befc45e907611180b4d3763c4154564cf89 /src/libstd
parent3e4be02b80a3dd27bce20870958fe0aef7e7336d (diff)
downloadrust-f798674b86382929ca17c88de422a6e2fdb27f2a.tar.gz
rust-f798674b86382929ca17c88de422a6e2fdb27f2a.zip
std: Stabilize the `net` module
This commit performs a stabilization pass over the std::net module,
incorporating the changes from RFC 923. Specifically, the following actions were
taken:

Stable functionality:

* `net` (the name)
* `Shutdown`
* `Shutdown::{Read, Write, Both}`
* `lookup_host`
* `LookupHost`
* `SocketAddr`
* `SocketAddr::{V4, V6}`
* `SocketAddr::port`
* `SocketAddrV4`
* `SocketAddrV4::{new, ip, port}`
* `SocketAddrV6`
* `SocketAddrV4::{new, ip, port, flowinfo, scope_id}`
* Common trait impls for socket addr structures
* `ToSocketAddrs`
* `ToSocketAddrs::Iter`
* `ToSocketAddrs::to_socket_addrs`
* `ToSocketAddrs for {SocketAddr*, (Ipv*Addr, u16), str, (str, u16)}`
* `Ipv4Addr`
* `Ipv4Addr::{new, octets, to_ipv6_compatible, to_ipv6_mapped}`
* `Ipv6Addr`
* `Ipv6Addr::{new, segments, to_ipv4}`
* `TcpStream`
* `TcpStream::connect`
* `TcpStream::{peer_addr, local_addr, shutdown, try_clone}`
* `{Read,Write} for {TcpStream, &TcpStream}`
* `TcpListener`
* `TcpListener::bind`
* `TcpListener::{local_addr, try_clone, accept, incoming}`
* `Incoming`
* `UdpSocket`
* `UdpSocket::bind`
* `UdpSocket::{recv_from, send_to, local_addr, try_clone}`

Unstable functionality:

* Extra methods on `Ipv{4,6}Addr` for various methods of inspecting the address
  and determining qualities of it.
* Extra methods on `TcpStream` to configure various protocol options.
* Extra methods on `UdpSocket` to configure various protocol options.

Deprecated functionality:

* The `socket_addr` method has been renamed to `local_addr`

This commit is a breaking change due to the restructuring of the `SocketAddr`
type as well as the renaming of the `socket_addr` method. Migration should be
fairly straightforward, however, after accounting for the new level of
abstraction in `SocketAddr` (protocol distinction at the socket address level,
not the IP address).

[breaking-change]
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/net/addr.rs395
-rw-r--r--src/libstd/net/ip.rs65
-rw-r--r--src/libstd/net/mod.rs17
-rw-r--r--src/libstd/net/parser.rs26
-rw-r--r--src/libstd/net/tcp.rs39
-rw-r--r--src/libstd/net/test.rs11
-rw-r--r--src/libstd/net/udp.rs30
-rw-r--r--src/libstd/sys/common/net2.rs32
-rw-r--r--src/libstd/sys/unix/net.rs8
-rw-r--r--src/libstd/sys/windows/net.rs8
10 files changed, 404 insertions, 227 deletions
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index 101aae3eb24..702f81db8e2 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -15,150 +15,220 @@ use hash;
 use io;
 use libc::{self, socklen_t, sa_family_t};
 use mem;
-use net::{IpAddr, lookup_host, ntoh, hton};
+use net::{lookup_host, ntoh, hton, Ipv4Addr, Ipv6Addr};
 use option;
 use sys_common::{FromInner, AsInner, IntoInner};
 use vec;
 
-/// Representation of a socket address for networking applications
+/// Representation of a socket address for networking applications.
 ///
-/// A socket address consists of at least an (ip, port) pair and may also
-/// contain other information depending on the protocol.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct SocketAddr {
-    repr: Repr,
+/// A socket address can either represent the IPv4 or IPv6 protocol and is
+/// paired with at least a port number as well. Each protocol may have more
+/// specific information about the address available to it as well.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SocketAddr {
+    /// An IPv4 socket address which is a (ip, port) combination.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V4(SocketAddrV4),
+    /// An IPv6 socket address
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V6(SocketAddrV6),
 }
 
+/// An IPv4 socket address which is a (ip, port) combination.
 #[derive(Copy)]
-enum Repr {
-    V4(libc::sockaddr_in),
-    V6(libc::sockaddr_in6),
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV4 { inner: libc::sockaddr_in }
+
+/// An IPv6 socket address
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV6 { inner: libc::sockaddr_in6 }
 
 impl SocketAddr {
+    /// Gets the port number associated with this socket address
+    #[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(),
+        }
+    }
+}
+
+impl SocketAddrV4 {
     /// Creates a new socket address from the (ip, port) pair.
-    pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
-        let repr = match ip {
-            IpAddr::V4(ref ip) => {
-                Repr::V4(libc::sockaddr_in {
-                    sin_family: libc::AF_INET as sa_family_t,
-                    sin_port: hton(port),
-                    sin_addr: *ip.as_inner(),
-                    .. unsafe { mem::zeroed() }
-                })
-            }
-            IpAddr::V6(ref ip) => {
-                Repr::V6(libc::sockaddr_in6 {
-                    sin6_family: libc::AF_INET6 as sa_family_t,
-                    sin6_port: hton(port),
-                    sin6_addr: *ip.as_inner(),
-                    .. unsafe { mem::zeroed() }
-                })
-            }
-        };
-        SocketAddr { repr: repr }
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
+        SocketAddrV4 {
+            inner: libc::sockaddr_in {
+                sin_family: libc::AF_INET as sa_family_t,
+                sin_port: hton(port),
+                sin_addr: *ip.as_inner(),
+                .. unsafe { mem::zeroed() }
+            },
+        }
     }
 
     /// Gets the IP address associated with this socket address.
-    pub fn ip(&self) -> IpAddr {
-        match self.repr {
-            Repr::V4(ref sa) => IpAddr::V4(FromInner::from_inner(sa.sin_addr)),
-            Repr::V6(ref sa) => IpAddr::V6(FromInner::from_inner(sa.sin6_addr)),
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn ip(&self) -> &Ipv4Addr {
+        unsafe {
+            &*(&self.inner.sin_addr as *const libc::in_addr as *const Ipv4Addr)
         }
     }
 
     /// Gets the port number associated with this socket address
-    pub fn port(&self) -> u16 {
-        match self.repr {
-            Repr::V4(ref sa) => ntoh(sa.sin_port),
-            Repr::V6(ref sa) => ntoh(sa.sin6_port),
-        }
-    }
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn port(&self) -> u16 { ntoh(self.inner.sin_port) }
+}
 
-    fn set_port(&mut self, port: u16) {
-        match self.repr {
-            Repr::V4(ref mut sa) => sa.sin_port = hton(port),
-            Repr::V6(ref mut sa) => sa.sin6_port = hton(port),
+impl SocketAddrV6 {
+    /// Creates a new socket address from the ip/port/flowinfo/scope_id
+    /// components.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32)
+               -> SocketAddrV6 {
+        SocketAddrV6 {
+            inner: libc::sockaddr_in6 {
+                sin6_family: libc::AF_INET6 as sa_family_t,
+                sin6_port: hton(port),
+                sin6_addr: *ip.as_inner(),
+                sin6_flowinfo: hton(flowinfo),
+                sin6_scope_id: hton(scope_id),
+                .. unsafe { mem::zeroed() }
+            },
         }
     }
-}
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self.repr {
-            Repr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
-            Repr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
+    /// Gets the IP address associated with this socket address.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn ip(&self) -> &Ipv6Addr {
+        unsafe {
+            &*(&self.inner.sin6_addr as *const libc::in6_addr as *const Ipv6Addr)
         }
     }
+
+    /// Gets the port number associated with this socket address
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn port(&self) -> u16 { ntoh(self.inner.sin6_port) }
+
+    /// Gets scope ID associated with this address, corresponding to the
+    /// `sin6_flowinfo` field in C.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn flowinfo(&self) -> u32 { ntoh(self.inner.sin6_flowinfo) }
+
+    /// Gets scope ID associated with this address, corresponding to the
+    /// `sin6_scope_id` field in C.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn scope_id(&self) -> u32 { ntoh(self.inner.sin6_scope_id) }
 }
 
-impl FromInner<libc::sockaddr_in> for SocketAddr {
-    fn from_inner(addr: libc::sockaddr_in) -> SocketAddr {
-        SocketAddr { repr: Repr::V4(addr) }
+impl FromInner<libc::sockaddr_in> for SocketAddrV4 {
+    fn from_inner(addr: libc::sockaddr_in) -> SocketAddrV4 {
+        SocketAddrV4 { inner: addr }
     }
 }
 
-impl FromInner<libc::sockaddr_in6> for SocketAddr {
-    fn from_inner(addr: libc::sockaddr_in6) -> SocketAddr {
-        SocketAddr { repr: Repr::V6(addr) }
+impl FromInner<libc::sockaddr_in6> for SocketAddrV6 {
+    fn from_inner(addr: libc::sockaddr_in6) -> SocketAddrV6 {
+        SocketAddrV6 { inner: addr }
     }
 }
 
 impl<'a> IntoInner<(*const libc::sockaddr, socklen_t)> for &'a SocketAddr {
     fn into_inner(self) -> (*const libc::sockaddr, socklen_t) {
-        match self.repr {
-            Repr::V4(ref a) => {
+        match *self {
+            SocketAddr::V4(ref a) => {
                 (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
             }
-            Repr::V6(ref a) => {
+            SocketAddr::V6(ref a) => {
                 (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
             }
         }
     }
 }
 
-impl fmt::Debug for SocketAddr {
+#[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)
     }
 }
 
-impl Clone for Repr {
-    fn clone(&self) -> Repr { *self }
+#[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())
+    }
 }
 
-impl PartialEq for Repr {
-    fn eq(&self, other: &Repr) -> bool {
-        match (*self, *other) {
-            (Repr::V4(ref a), Repr::V4(ref b)) => {
-                a.sin_port == b.sin_port &&
-                    a.sin_addr.s_addr == b.sin_addr.s_addr
-            }
-            (Repr::V6(ref a), Repr::V6(ref b)) => {
-                a.sin6_port == b.sin6_port &&
-                    a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
-                    a.sin6_flowinfo == b.sin6_flowinfo &&
-                    a.sin6_scope_id == b.sin6_scope_id
-            }
-            _ => false,
-        }
+#[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
     }
 }
-impl Eq for Repr {}
+#[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 Repr {
+impl hash::Hash for SocketAddrV4 {
     fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        match *self {
-            Repr::V4(ref a) => {
-                (a.sin_family, a.sin_port, a.sin_addr.s_addr).hash(s)
-            }
-            Repr::V6(ref a) => {
-                (a.sin6_family, a.sin6_port, &a.sin6_addr.s6_addr,
-                 a.sin6_flowinfo, a.sin6_scope_id).hash(s)
-            }
-        }
+        (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)
     }
 }
 
@@ -168,12 +238,13 @@ impl hash::Hash for Repr {
 /// 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 identity function.
+///  * `SocketAddr`, `SocketAddrV4`, `SocketAddrV6` - `to_socket_addrs` is
+///    identity function.
 ///
-///  * `(IpAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially.
+///  * `(IpvNAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially.
 ///
 ///  * `(&str, u16)` - the string should be either a string representation of an
-///    IP address expected by `FromStr` implementation for `IpAddr` or a host
+///    IP address expected by `FromStr` implementation for `IpvNAddr` or a host
 ///    name.
 ///
 ///  * `&str` - the string should be either a string representation of a
@@ -192,18 +263,18 @@ impl hash::Hash for Repr {
 /// Some examples:
 ///
 /// ```no_run
-/// use std::net::{IpAddr, SocketAddr, TcpStream, UdpSocket, TcpListener};
+/// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr};
 ///
 /// fn main() {
-///     let ip = IpAddr::new_v4(127, 0, 0, 1);
+///     let ip = Ipv4Addr::new(127, 0, 0, 1);
 ///     let port = 12345;
 ///
 ///     // The following lines are equivalent modulo possible "localhost" name
 ///     // resolution differences
-///     let tcp_s = TcpStream::connect(&SocketAddr::new(ip, port));
-///     let tcp_s = TcpStream::connect(&(ip, port));
-///     let tcp_s = TcpStream::connect(&("127.0.0.1", port));
-///     let tcp_s = TcpStream::connect(&("localhost", port));
+///     let tcp_s = TcpStream::connect(SocketAddrV4::new(ip, port));
+///     let tcp_s = TcpStream::connect((ip, port));
+///     let tcp_s = TcpStream::connect(("127.0.0.1", port));
+///     let tcp_s = TcpStream::connect(("localhost", port));
 ///     let tcp_s = TcpStream::connect("127.0.0.1:12345");
 ///     let tcp_s = TcpStream::connect("localhost:12345");
 ///
@@ -211,13 +282,15 @@ impl hash::Hash for Repr {
 ///     // behave similarly
 ///     let tcp_l = TcpListener::bind("localhost:12345");
 ///
-///     let mut udp_s = UdpSocket::bind(&("127.0.0.1", port)).unwrap();
-///     udp_s.send_to(&[7], &(ip, 23451));
+///     let mut udp_s = UdpSocket::bind(("127.0.0.1", port)).unwrap();
+///     udp_s.send_to(&[7], (ip, 23451));
 /// }
 /// ```
+#[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.
@@ -231,9 +304,11 @@ pub trait ToSocketAddrs {
     /// # Errors
     ///
     /// Any errors encountered during resolution will be returned as an `Err`.
+    #[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>> {
@@ -241,31 +316,72 @@ impl ToSocketAddrs for SocketAddr {
     }
 }
 
-impl ToSocketAddrs for (IpAddr, u16) {
+#[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 (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;
-        Ok(Some(SocketAddr::new(ip, port)).into_iter())
+        SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs()
     }
 }
 
 fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
     let ips = try!(lookup_host(s));
     let v: Vec<_> = try!(ips.map(|a| {
-        a.map(|mut a| { a.set_port(p); a })
+        a.map(|a| {
+            match a {
+                SocketAddr::V4(ref a) => {
+                    SocketAddr::V4(SocketAddrV4::new(*a.ip(), p))
+                }
+                SocketAddr::V6(ref a) => {
+                    SocketAddr::V6(SocketAddrV6::new(*a.ip(), p, a.flowinfo(),
+                                                     a.scope_id()))
+                }
+            }
+        })
     }).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 IpAddr first
-        match host.parse().ok() {
-            Some(addr) => return Ok(vec![SocketAddr::new(addr, port)].into_iter()),
-            None => {}
+        // 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)
@@ -273,6 +389,7 @@ impl<'a> ToSocketAddrs for (&'a str, u16) {
 }
 
 // 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>> {
@@ -322,16 +439,16 @@ mod tests {
         assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
 
         // out of range
-        let none: Option<IpAddr> = "256.0.0.1".parse().ok();
+        let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
         assert_eq!(None, none);
         // too short
-        let none: Option<IpAddr> = "255.0.0".parse().ok();
+        let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
         assert_eq!(None, none);
         // too long
-        let none: Option<IpAddr> = "255.0.0.1.2".parse().ok();
+        let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
         assert_eq!(None, none);
         // no number between dots
-        let none: Option<IpAddr> = "255.0..1".parse().ok();
+        let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
         assert_eq!(None, none);
     }
 
@@ -347,19 +464,19 @@ mod tests {
                 "2a02:6b8::11:11".parse());
 
         // too long group
-        let none: Option<IpAddr> = "::00000".parse().ok();
+        let none: Option<Ipv6Addr> = "::00000".parse().ok();
         assert_eq!(None, none);
         // too short
-        let none: Option<IpAddr> = "1:2:3:4:5:6:7".parse().ok();
+        let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
         assert_eq!(None, none);
         // too long
-        let none: Option<IpAddr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+        let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
         assert_eq!(None, none);
         // triple colon
-        let none: Option<IpAddr> = "1:2:::6:7:8".parse().ok();
+        let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
         assert_eq!(None, none);
         // two double colons
-        let none: Option<IpAddr> = "1:2::6::8".parse().ok();
+        let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
         assert_eq!(None, none);
     }
 
@@ -375,24 +492,24 @@ mod tests {
                 "2001:db8:122:c000:2:2100:192.0.2.33".parse());
 
         // colon after v4
-        let none: Option<IpAddr> = "::127.0.0.1:".parse().ok();
+        let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
         assert_eq!(None, none);
         // not enough groups
-        let none: Option<IpAddr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+        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<IpAddr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+        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(SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 80)),
-                "77.88.21.11:80".parse());
-        assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
-                "[2a02:6b8:0:1::1]:53".parse());
-        assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
-                "[::127.0.0.1]:22".parse());
+        assert_eq!(Ok(sa4(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(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
+                   "[::127.0.0.1]:22".parse());
 
         // without port
         let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
@@ -555,39 +672,47 @@ mod tests {
 
     #[test]
     fn to_socket_addr_socketaddr() {
-        let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 12345);
+        let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
         assert_eq!(Ok(vec![a]), tsa(a));
     }
 
+    fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
+        SocketAddr::V4(SocketAddrV4::new(a, p))
+    }
+
+    fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
+        SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
+    }
+
     #[test]
     fn to_socket_addr_ipaddr_u16() {
-        let a = IpAddr::new_v4(77, 88, 21, 11);
+        let a = Ipv4Addr::new(77, 88, 21, 11);
         let p = 12345;
-        let e = SocketAddr::new(a, p);
+        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 = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352);
+        let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
         assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
 
-        let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+        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 = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924);
+        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 = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352);
+        let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
         assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
 
-        let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+        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 = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924);
+        let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
         assert!(tsa("localhost:23924").unwrap().contains(&a));
     }
 
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index d699886e577..0c33343b0c6 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -8,6 +8,10 @@
 // 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 stable")]
+
 use prelude::v1::*;
 
 use cmp::Ordering;
@@ -19,12 +23,14 @@ use net::{hton, ntoh};
 
 /// Representation of an IPv4 address.
 #[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ipv4Addr {
     inner: libc::in_addr,
 }
 
 /// Representation of an IPv6 address.
 #[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ipv6Addr {
     inner: libc::in6_addr,
 }
@@ -41,46 +47,11 @@ pub enum Ipv6MulticastScope {
     Global
 }
 
-/// Enumeration of possible IP addresses
-#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
-pub enum IpAddr {
-    /// An IPv4 address.
-    V4(Ipv4Addr),
-    /// An IPv6 address.
-    V6(Ipv6Addr)
-}
-
-impl IpAddr {
-    /// Create a new IpAddr that contains an IPv4 address.
-    ///
-    /// The result will represent the IP address a.b.c.d
-    pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
-        IpAddr::V4(Ipv4Addr::new(a, b, c, d))
-    }
-
-    /// Create a new IpAddr that contains an IPv6 address.
-    ///
-    /// The result will represent the IP address a:b:c:d:e:f
-    pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
-                  h: u16) -> IpAddr {
-        IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for IpAddr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            IpAddr::V4(v4) => v4.fmt(f),
-            IpAddr::V6(v6) => v6.fmt(f)
-        }
-    }
-}
-
 impl Ipv4Addr {
     /// Create a new IPv4 address from four eight-bit octets.
     ///
     /// The result will represent the IP address a.b.c.d
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         Ipv4Addr {
             inner: libc::in_addr {
@@ -93,6 +64,7 @@ impl Ipv4Addr {
     }
 
     /// Returns the four eight-bit integers that make up this address
+    #[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]
@@ -148,6 +120,7 @@ impl Ipv4Addr {
     /// Convert this address to an IPv4-compatible IPv6 address
     ///
     /// a.b.c.d becomes ::a.b.c.d
+    #[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,
@@ -157,6 +130,7 @@ impl Ipv4Addr {
     /// Convert this address to an IPv4-mapped IPv6 address
     ///
     /// a.b.c.d becomes ::ffff:a.b.c.d
+    #[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,
@@ -165,6 +139,7 @@ impl Ipv4Addr {
 
 }
 
+#[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();
@@ -172,21 +147,26 @@ impl fmt::Display for Ipv4Addr {
     }
 }
 
+#[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 = "rust1", since = "1.0.0")]
 impl Eq for Ipv4Addr {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -196,12 +176,14 @@ impl hash::Hash for Ipv4Addr {
     }
 }
 
+#[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 = "rust1", since = "1.0.0")]
 impl Ord for Ipv4Addr {
     fn cmp(&self, other: &Ipv4Addr) -> Ordering {
         self.inner.s_addr.cmp(&other.inner.s_addr)
@@ -221,6 +203,7 @@ impl Ipv6Addr {
     /// Create a new IPv6 address from eight 16-bit segments.
     ///
     /// The result will represent the IP address a:b:c:d:e:f
+    #[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 {
         Ipv6Addr {
@@ -232,6 +215,7 @@ impl Ipv6Addr {
     }
 
     /// Return the eight 16-bit segments that make up this address
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn segments(&self) -> [u16; 8] {
         [ntoh(self.inner.s6_addr[0]),
          ntoh(self.inner.s6_addr[1]),
@@ -324,6 +308,7 @@ impl Ipv6Addr {
     /// neither IPv4-compatible or IPv4-mapped.
     ///
     /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+    #[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 => {
@@ -335,6 +320,7 @@ impl Ipv6Addr {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv6Addr {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match self.segments() {
@@ -405,21 +391,26 @@ impl fmt::Display for Ipv6Addr {
     }
 }
 
+#[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 = "rust1", since = "1.0.0")]
 impl Eq for Ipv6Addr {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -429,12 +420,14 @@ impl hash::Hash for Ipv6Addr {
     }
 }
 
+#[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 = "rust1", since = "1.0.0")]
 impl Ord for Ipv6Addr {
     fn cmp(&self, other: &Ipv6Addr) -> Ordering {
         self.inner.s6_addr.cmp(&other.inner.s6_addr)
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
index b8cb8cb5289..5f7c7babbcf 100644
--- a/src/libstd/net/mod.rs
+++ b/src/libstd/net/mod.rs
@@ -14,7 +14,7 @@
 //! > development. At this time it is still recommended to use the `old_io`
 //! > module while the details of this module shake out.
 
-#![unstable(feature = "net")]
+#![stable(feature = "rust1", since = "1.0.0")]
 
 use prelude::v1::*;
 
@@ -22,8 +22,8 @@ use io::{self, Error, ErrorKind};
 use num::Int;
 use sys_common::net2 as net_imp;
 
-pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
-pub use self::addr::{SocketAddr, ToSocketAddrs};
+pub use self::ip::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 pub use self::tcp::{TcpStream, TcpListener};
 pub use self::udp::UdpSocket;
 
@@ -37,23 +37,27 @@ mod parser;
 /// Possible values which can be passed to the `shutdown` method of `TcpStream`
 /// and `UdpSocket`.
 #[derive(Copy, Clone, PartialEq)]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub enum Shutdown {
     /// Indicates that the reading portion of this stream/socket should be shut
     /// down. All currently blocked and future reads will return `Ok(0)`.
+    #[stable(feature = "rust1", since = "1.0.0")]
     Read,
     /// Indicates that the writing portion of this stream/socket should be shut
     /// down. All currently blocked and future writes will return an error.
+    #[stable(feature = "rust1", since = "1.0.0")]
     Write,
     /// Shut down both the reading and writing portions of this stream.
     ///
     /// See `Shutdown::Read` and `Shutdown::Write` for more information.
-    Both
+    #[stable(feature = "rust1", since = "1.0.0")]
+    Both,
 }
 
 fn hton<I: Int>(i: I) -> I { i.to_be() }
 fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
 
-fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
+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;
@@ -70,8 +74,10 @@ fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<
 }
 
 /// An iterator over `SocketAddr` values returned from a host lookup operation.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct LookupHost(net_imp::LookupHost);
 
+#[stable(feature = "rust1", since = "1.0.0")]
 impl Iterator for LookupHost {
     type Item = io::Result<SocketAddr>;
     fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
@@ -94,6 +100,7 @@ impl Iterator for LookupHost {
 /// # Ok(())
 /// # }
 /// ```
+#[stable(feature = "rust1", since = "1.0.0")]
 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
     net_imp::lookup_host(host).map(LookupHost)
 }
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
index aa54a432d62..9843a152718 100644
--- a/src/libstd/net/parser.rs
+++ b/src/libstd/net/parser.rs
@@ -16,7 +16,7 @@
 use prelude::v1::*;
 
 use str::FromStr;
-use net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
+use net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
@@ -24,6 +24,11 @@ struct Parser<'a> {
     pos: usize,
 }
 
+enum IpAddr {
+    V4(Ipv4Addr),
+    V6(Ipv6Addr),
+}
+
 impl<'a> Parser<'a> {
     fn new(s: &'a str) -> Parser<'a> {
         Parser {
@@ -281,18 +286,13 @@ impl<'a> Parser<'a> {
         let port  = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
 
         // host, colon, port
-        self.read_seq_3::<IpAddr, char, u16, _, _, _>(ip_addr, colon, port)
-                .map(|t| match t { (ip, _, port) => SocketAddr::new(ip, port) })
-    }
-}
-
-impl FromStr for IpAddr {
-    type Err = ParseError;
-    fn from_str(s: &str) -> Result<IpAddr, ParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
-            Some(s) => Ok(s),
-            None => Err(ParseError),
-        }
+        self.read_seq_3(ip_addr, colon, port).map(|t| {
+            let (ip, _, port): (IpAddr, char, u16) = t;
+            match ip {
+                IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
+                IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
+            }
+        })
     }
 }
 
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 76c04835473..501ba2dc2c1 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![unstable(feature = "tcp", reason = "remaining functions have not been \
+                                       scrutinized enough to be stabilized")]
+
 use prelude::v1::*;
 use io::prelude::*;
 
@@ -35,6 +38,7 @@ use sys_common::AsInner;
 ///     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 structure representing a socket server.
@@ -67,12 +71,14 @@ pub struct TcpStream(net_imp::TcpStream);
 /// // close the socket server
 /// drop(listener);
 /// ```
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct TcpListener(net_imp::TcpListener);
 
 /// An infinite iterator over the connections from a `TcpListener`.
 ///
 /// This iterator will infinitely yield `Some` of the accepted connections. It
 /// is equivalent to calling `accept` in a loop.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Incoming<'a> { listener: &'a TcpListener }
 
 impl TcpStream {
@@ -81,25 +87,36 @@ impl TcpStream {
     /// `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.
-    pub fn connect<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<TcpStream> {
+    #[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)
     }
 
     /// Returns the socket address of the remote peer of this TCP connection.
+    #[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.
+    #[unstable(feature = "net")]
+    #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
         self.0.socket_addr()
     }
 
+    /// Returns the socket address of the local half of this TCP connection.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
     /// Shut 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`).
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
         self.0.shutdown(how)
     }
@@ -110,6 +127,7 @@ impl TcpStream {
     /// 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.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_clone(&self) -> io::Result<TcpStream> {
         self.0.duplicate().map(TcpStream)
     }
@@ -129,16 +147,20 @@ impl TcpStream {
     }
 }
 
+#[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) }
 }
+#[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) }
 }
+#[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(()) }
@@ -160,11 +182,20 @@ impl TcpListener {
     ///
     /// The address type can be any implementer of `ToSocketAddrs` trait. See
     /// its documentation for concrete examples.
-    pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<TcpListener> {
+    #[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.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
+    /// Deprecated, renamed to local_addr
+    #[unstable(feature = "net")]
+    #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
         self.0.socket_addr()
     }
@@ -174,6 +205,7 @@ impl TcpListener {
     /// 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.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_clone(&self) -> io::Result<TcpListener> {
         self.0.duplicate().map(TcpListener)
     }
@@ -183,6 +215,7 @@ impl TcpListener {
     /// 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.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         self.0.accept().map(|(a, b)| (TcpStream(a), b))
     }
@@ -192,11 +225,13 @@ impl TcpListener {
     ///
     /// The returned iterator will never returned `None` and will also not yield
     /// the peer's `SocketAddr` structure.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn incoming(&self) -> Incoming {
         Incoming { listener: self }
     }
 }
 
+#[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>> {
diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs
index dbebede9f50..3d42472f0fc 100644
--- a/src/libstd/net/test.rs
+++ b/src/libstd/net/test.rs
@@ -11,19 +11,20 @@
 use prelude::v1::*;
 
 use env;
-use net::{SocketAddr, IpAddr};
+use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
 use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
 
 static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
 
 pub fn next_test_ip4() -> SocketAddr {
-    SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1),
-                    PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
+    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 {
-    SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1),
-                    PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
+    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))
 }
 
 // The bots run multiple builds at the same time, and these builds
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index 041e6551ff5..1ace1957526 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -8,10 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![unstable(feature = "udp", reason = "remaining functions have not been \
+                                       scrutinized enough to be stabilized")]
+
 use prelude::v1::*;
 
 use io::{self, Error, ErrorKind};
-use net::{ToSocketAddrs, SocketAddr, IpAddr};
+use net::{ToSocketAddrs, SocketAddr};
 use sys_common::net2 as net_imp;
 use sys_common::AsInner;
 
@@ -41,6 +44,7 @@ use sys_common::AsInner;
 /// # Ok(())
 /// # }
 /// ```
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct UdpSocket(net_imp::UdpSocket);
 
 impl UdpSocket {
@@ -48,12 +52,14 @@ impl UdpSocket {
     ///
     /// Address type can be any implementor of `ToSocketAddr` trait. See its
     /// documentation for concrete examples.
-    pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<UdpSocket> {
+    #[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 data from the socket. On success, returns the number of bytes
     /// read and the address from whence the data came.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
         self.0.recv_from(buf)
     }
@@ -63,8 +69,9 @@ impl UdpSocket {
     ///
     /// Address type can be any implementor of `ToSocketAddrs` trait. See its
     /// documentation for concrete examples.
-    pub fn send_to<A: ToSocketAddrs + ?Sized>(&self, buf: &[u8], addr: &A)
-                                              -> io::Result<usize> {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A)
+                                     -> io::Result<usize> {
         match try!(addr.to_socket_addrs()).next() {
             Some(addr) => self.0.send_to(buf, &addr),
             None => Err(Error::new(ErrorKind::InvalidInput,
@@ -73,15 +80,24 @@ impl UdpSocket {
     }
 
     /// Returns the socket address that this socket was created from.
+    #[unstable(feature = "net")]
+    #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
         self.0.socket_addr()
     }
 
+    /// Returns the socket address that this socket was created from.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
     /// Create 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.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_clone(&self) -> io::Result<UdpSocket> {
         self.0.duplicate().map(UdpSocket)
     }
@@ -99,12 +115,12 @@ impl UdpSocket {
     }
 
     /// Joins a multicast IP address (becomes a member of it)
-    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+    pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
         self.0.join_multicast(multi)
     }
 
     /// Leaves a multicast IP address (drops membership from it)
-    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+    pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
         self.0.leave_multicast(multi)
     }
 
@@ -151,7 +167,7 @@ mod tests {
     #[cfg_attr(any(windows, target_os = "android"), ignore)]
     #[test]
     fn bind_error() {
-        let addr = SocketAddr::new(IpAddr::new_v4(0, 0, 0, 0), 1);
+        let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 1);
         match UdpSocket::bind(&addr) {
             Ok(..) => panic!(),
             Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs
index af5b49a4239..25aeab1b4ff 100644
--- a/src/libstd/sys/common/net2.rs
+++ b/src/libstd/sys/common/net2.rs
@@ -14,7 +14,7 @@ use ffi::CString;
 use io::{self, Error, ErrorKind};
 use libc::{self, c_int, c_char, c_void, socklen_t};
 use mem;
-use net::{IpAddr, SocketAddr, Shutdown};
+use net::{SocketAddr, Shutdown};
 use sys::c;
 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
 use sys_common::{AsInner, FromInner, IntoInner};
@@ -63,15 +63,15 @@ fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
     match storage.ss_family as libc::c_int {
         libc::AF_INET => {
             assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
-            Ok(FromInner::from_inner(unsafe {
+            Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
                 *(storage as *const _ as *const libc::sockaddr_in)
-            }))
+            })))
         }
         libc::AF_INET6 => {
             assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
-            Ok(FromInner::from_inner(unsafe {
+            Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
                 *(storage as *const _ as *const libc::sockaddr_in6)
-            }))
+            })))
         }
         _ => {
             Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
@@ -334,39 +334,39 @@ impl UdpSocket {
                    libc::IP_MULTICAST_LOOP, on as c_int)
     }
 
-    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+    pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
         match *multi {
-            IpAddr::V4(..) => {
+            SocketAddr::V4(..) => {
                 self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
             }
-            IpAddr::V6(..) => {
+            SocketAddr::V6(..) => {
                 self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
             }
         }
     }
-    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+    pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
         match *multi {
-            IpAddr::V4(..) => {
+            SocketAddr::V4(..) => {
                 self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
             }
-            IpAddr::V6(..) => {
+            SocketAddr::V6(..) => {
                 self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
             }
         }
     }
-    fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
+    fn set_membership(&self, addr: &SocketAddr, opt: c_int) -> io::Result<()> {
         match *addr {
-            IpAddr::V4(ref addr) => {
+            SocketAddr::V4(ref addr) => {
                 let mreq = libc::ip_mreq {
-                    imr_multiaddr: *addr.as_inner(),
+                    imr_multiaddr: *addr.ip().as_inner(),
                     // interface == INADDR_ANY
                     imr_interface: libc::in_addr { s_addr: 0x0 },
                 };
                 setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
             }
-            IpAddr::V6(ref addr) => {
+            SocketAddr::V6(ref addr) => {
                 let mreq = libc::ip6_mreq {
-                    ipv6mr_multiaddr: *addr.as_inner(),
+                    ipv6mr_multiaddr: *addr.ip().as_inner(),
                     ipv6mr_interface: 0,
                 };
                 setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 83b6a14b78d..b22fa33e562 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -15,7 +15,7 @@ use io;
 use libc::{self, c_int, size_t};
 use str;
 use sys::c;
-use net::{SocketAddr, IpAddr};
+use net::SocketAddr;
 use sys::fd::FileDesc;
 use sys_common::AsInner;
 
@@ -40,9 +40,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
 
 impl Socket {
     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
-        let fam = match addr.ip() {
-            IpAddr::V4(..) => libc::AF_INET,
-            IpAddr::V6(..) => libc::AF_INET6,
+        let fam = match *addr {
+            SocketAddr::V4(..) => libc::AF_INET,
+            SocketAddr::V6(..) => libc::AF_INET6,
         };
         unsafe {
             let fd = try!(cvt(libc::socket(fam, ty, 0)));
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
index 6caa4df5dfe..e092faf4935 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -14,7 +14,7 @@ use io;
 use libc::consts::os::extra::INVALID_SOCKET;
 use libc::{self, c_int, c_void};
 use mem;
-use net::{SocketAddr, IpAddr};
+use net::SocketAddr;
 use num::{SignedInt, Int};
 use rt;
 use sync::{Once, ONCE_INIT};
@@ -73,9 +73,9 @@ pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
 
 impl Socket {
     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
-        let fam = match addr.ip() {
-            IpAddr::V4(..) => libc::AF_INET,
-            IpAddr::V6(..) => libc::AF_INET6,
+        let fam = match *addr {
+            SocketAddr::V4(..) => libc::AF_INET,
+            SocketAddr::V6(..) => libc::AF_INET6,
         };
         match unsafe { libc::socket(fam, ty, 0) } {
             INVALID_SOCKET => Err(last_error()),