]> git.proxmox.com Git - rustc.git/blobdiff - src/libstd/net/addr.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / libstd / net / addr.rs
index 886f252fb192672b086bc347b87f8b0acae2d130..20dc5b3801ba410560d75100480ee17c6f1099d9 100644 (file)
@@ -8,17 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use fmt;
 use hash;
 use io;
-use libc::{self, socklen_t, sa_family_t};
 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;
 
 /// Representation of a socket address for networking applications.
 ///
@@ -30,25 +30,25 @@ use vec;
 pub enum SocketAddr {
     /// An IPv4 socket address which is a (ip, port) combination.
     #[stable(feature = "rust1", since = "1.0.0")]
-    V4(SocketAddrV4),
+    V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
     /// An IPv6 socket address
     #[stable(feature = "rust1", since = "1.0.0")]
-    V6(SocketAddrV6),
+    V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
 }
 
 /// An IPv4 socket address which is a (ip, port) combination.
 #[derive(Copy)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV4 { inner: libc::sockaddr_in }
+pub struct SocketAddrV4 { inner: c::sockaddr_in }
 
-/// An IPv6 socket address
+/// An IPv6 socket address.
 #[derive(Copy)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV6 { inner: libc::sockaddr_in6 }
+pub struct SocketAddrV6 { inner: c::sockaddr_in6 }
 
 impl SocketAddr {
     /// Creates a new socket address from the (ip, port) pair.
-    #[unstable(feature = "ip_addr", reason = "recent addition")]
+    #[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)),
@@ -56,8 +56,8 @@ impl SocketAddr {
         }
     }
 
-    /// Gets the IP address associated with this socket address.
-    #[unstable(feature = "ip_addr", reason = "recent addition")]
+    /// Returns the IP address associated with this socket address.
+    #[stable(feature = "ip_addr", since = "1.7.0")]
     pub fn ip(&self) -> IpAddr {
         match *self {
             SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
@@ -65,7 +65,18 @@ impl SocketAddr {
         }
     }
 
-    /// Gets the port number associated with this socket address
+    /// Change the IP address associated with this socket address.
+    #[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.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
         match *self {
@@ -73,6 +84,35 @@ impl SocketAddr {
             SocketAddr::V6(ref a) => a.port(),
         }
     }
+
+    /// Change the port number associated with this socket address.
+    #[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 in this `SocketAddr` is a valid IPv4 address,
+    /// false if it's a valid IPv6 address.
+    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    pub fn is_ipv4(&self) -> bool {
+        match *self {
+            SocketAddr::V4(_) => true,
+            SocketAddr::V6(_) => false,
+        }
+    }
+
+    /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address,
+    /// false if it's a valid IPv4 address.
+    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    pub fn is_ipv6(&self) -> bool {
+        match *self {
+            SocketAddr::V4(_) => false,
+            SocketAddr::V6(_) => true,
+        }
+    }
 }
 
 impl SocketAddrV4 {
@@ -80,8 +120,8 @@ impl SocketAddrV4 {
     #[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,
+            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() }
@@ -89,17 +129,31 @@ impl SocketAddrV4 {
         }
     }
 
-    /// Gets the IP address associated with this socket address.
+    /// Returns the IP address associated with this socket address.
     #[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)
+            &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr)
         }
     }
 
-    /// Gets the port number associated with this socket address
+    /// Change the IP address associated with this socket address.
+    #[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.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn port(&self) -> u16 { ntoh(self.inner.sin_port) }
+    pub fn port(&self) -> u16 {
+        ntoh(self.inner.sin_port)
+    }
+
+    /// Change the port number associated with this socket address.
+    #[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 {
@@ -109,60 +163,90 @@ impl SocketAddrV6 {
     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,
+            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: hton(flowinfo),
-                sin6_scope_id: hton(scope_id),
+                sin6_flowinfo: flowinfo,
+                sin6_scope_id: scope_id,
                 .. unsafe { mem::zeroed() }
             },
         }
     }
 
-    /// Gets the IP address associated with this socket address.
+    /// Returns 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)
+            &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr)
         }
     }
 
-    /// Gets the port number associated with this socket address
+    /// Change the IP address associated with this socket address.
+    #[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.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn port(&self) -> u16 { ntoh(self.inner.sin6_port) }
+    pub fn port(&self) -> u16 {
+        ntoh(self.inner.sin6_port)
+    }
+
+    /// Change the port number associated with this socket address.
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.inner.sin6_port = hton(new_port);
+    }
 
-    /// Gets scope ID associated with this address, corresponding to the
-    /// `sin6_flowinfo` field in C.
+    /// Returns the flow information 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) }
+    pub fn flowinfo(&self) -> u32 {
+        self.inner.sin6_flowinfo
+    }
+
+    /// Change the flow information associated with this socket address.
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+        self.inner.sin6_flowinfo = new_flowinfo;
+    }
 
-    /// Gets scope ID associated with this address, corresponding to the
-    /// `sin6_scope_id` field in C.
+    /// Returns the 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) }
+    pub fn scope_id(&self) -> u32 {
+        self.inner.sin6_scope_id
+    }
+
+    /// Change the scope ID associated with this socket address.
+    #[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<libc::sockaddr_in> for SocketAddrV4 {
-    fn from_inner(addr: libc::sockaddr_in) -> SocketAddrV4 {
+impl FromInner<c::sockaddr_in> for SocketAddrV4 {
+    fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
         SocketAddrV4 { inner: addr }
     }
 }
 
-impl FromInner<libc::sockaddr_in6> for SocketAddrV6 {
-    fn from_inner(addr: libc::sockaddr_in6) -> SocketAddrV6 {
+impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
+    fn from_inner(addr: c::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) {
+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 socklen_t)
+                (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 socklen_t)
+                (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
             }
         }
     }
@@ -278,10 +362,12 @@ impl hash::Hash for SocketAddrV6 {
 /// 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.
+///
 /// Some examples:
 ///
 /// ```no_run
-/// # #![feature(net)]
 /// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr};
 ///
 /// fn main() {
@@ -302,7 +388,7 @@ impl hash::Hash for SocketAddrV6 {
 ///     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));
+///     udp_s.send_to(&[7], (ip, 23451)).unwrap();
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -382,20 +468,8 @@ impl ToSocketAddrs for (Ipv6Addr, u16) {
 }
 
 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(|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());
+    let ips = lookup_host(s)?;
+    let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect();
     Ok(v.into_iter())
 }
 
@@ -425,9 +499,8 @@ 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
-        match self.parse().ok() {
-            Some(addr) => return Ok(vec![addr].into_iter()),
-            None => {}
+        if let Some(addr) = self.parse().ok() {
+            return Ok(vec![addr].into_iter());
         }
 
         macro_rules! try_opt {
@@ -449,6 +522,16 @@ impl ToSocketAddrs for str {
     }
 }
 
+#[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> {
@@ -456,267 +539,10 @@ impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
-    use prelude::v1::*;
-    use io;
     use net::*;
-    use net::Ipv6MulticastScope::*;
-
-    #[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);
-    }
-
-    #[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(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();
-        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 ipv4_properties() {
-        fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
-                 private: bool, link_local: bool, global: bool,
-                 multicast: 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);
-        }
-
-        //    address                unspec loopbk privt  linloc global multicast
-        check(&[0, 0, 0, 0],         true,  false, false, false, true,  false);
-        check(&[0, 0, 0, 1],         false, false, false, false, true,  false);
-        check(&[1, 0, 0, 0],         false, false, false, false, true,  false);
-        check(&[10, 9, 8, 7],        false, false, true,  false, false, false);
-        check(&[127, 1, 2, 3],       false, true,  false, false, false, false);
-        check(&[172, 31, 254, 253],  false, false, true,  false, false,  false);
-        check(&[169, 254, 253, 242], false, false, false, true,  false, false);
-        check(&[192, 168, 254, 253], false, false, true,  false, false, false);
-        check(&[224, 0, 0, 0],       false, false, false, false, true,  true);
-        check(&[239, 255, 255, 255], false, false, false, false, true,  true);
-        check(&[255, 255, 255, 255], false, false, false, false, true,  false);
-    }
-
-    #[test]
-    fn ipv6_properties() {
-        fn check(str_addr: &str, unspec: bool, loopback: bool,
-                 unique_local: bool, global: bool,
-                 u_link_local: bool, u_site_local: bool, u_global: bool,
-                 m_scope: Option<Ipv6MulticastScope>) {
-            let ip: Ipv6Addr = str_addr.parse().unwrap();
-            assert_eq!(str_addr, ip.to_string());
-
-            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.multicast_scope(), m_scope);
-            assert_eq!(ip.is_multicast(), m_scope.is_some());
-        }
-
-        //    unspec loopbk uniqlo global unill  unisl  uniglo mscope
-        check("::",
-              true,  false, false, true,  false, false, true,  None);
-        check("::1",
-              false, true,  false, false, false, false, false, None);
-        check("::0.0.0.2",
-              false, false, false, true,  false, false, true,  None);
-        check("1::",
-              false, false, false, true,  false, false, true,  None);
-        check("fc00::",
-              false, false, true,  false, false, false, false, None);
-        check("fdff:ffff::",
-              false, false, true,  false, false, false, false, None);
-        check("fe80:ffff::",
-              false, false, false, false, true,  false, false, None);
-        check("febf:ffff::",
-              false, false, false, false, true,  false, false, None);
-        check("fec0::",
-              false, false, false, false, false, true,  false, None);
-        check("ff01::",
-              false, false, false, false, false, false, false, Some(InterfaceLocal));
-        check("ff02::",
-              false, false, false, false, false, false, false, Some(LinkLocal));
-        check("ff03::",
-              false, false, false, false, false, false, false, Some(RealmLocal));
-        check("ff04::",
-              false, false, false, false, false, false, false, Some(AdminLocal));
-        check("ff05::",
-              false, false, false, false, false, false, false, Some(SiteLocal));
-        check("ff08::",
-              false, false, false, false, false, false, false, Some(OrganizationLocal));
-        check("ff0e::",
-              false, false, false, true,  false, false, false, Some(Global));
-    }
-
-    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()),
-        }
-    }
-
-    #[test]
-    fn to_socket_addr_socketaddr() {
-        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))
-    }
+    use net::test::{tsa, sa6, sa4};
 
     #[test]
     fn to_socket_addr_ipaddr_u16() {
@@ -750,9 +576,94 @@ mod tests {
         assert!(tsa("localhost:23924").unwrap().contains(&a));
     }
 
+    // FIXME: figure out why this fails on openbsd and bitrig and fix it
     #[test]
-    #[cfg(not(windows))]
+    #[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());
+    }
 }