Auto merge of #78802 - faern:simplify-socketaddr, r=joshtriplett

Implement network primitives with ideal Rust layout, not C system layout

This PR is the result of this internals forum thread: https://internals.rust-lang.org/t/why-are-socketaddrv4-socketaddrv6-based-on-low-level-sockaddr-in-6/13321.

Instead of basing `std:::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}` on system (C) structs, they are encoded in a more optimal and idiomatic Rust way.

This changes the public API of std by introducing structural equality impls for all four types here, which means that `match ipv4addr { SOME_CONSTANT => ... }` will now compile, whereas previously this was an error. No other intentional changes are introduced to public API.

It's possible to observe the current layout of these types (e.g., by pointer casting); most but not all libraries which were found by Crater to do this have had updates issued and affected versions yanked. See report below.

### Benefits of this change

- It will become possible to move these fundamental network types from `std` into `core` ([RFC](https://github.com/rust-lang/rfcs/pull/2832)).
- Some methods that can't be made `const fn`s today can be made `const fn`s with this change.
- `SocketAddrV4` only occupies 6 bytes instead of 16 bytes.
- These simple primitives become easier to read and uses less `unsafe`.
- Makes these types support structural equality, which means you can now (for instance) match an `Ipv4Addr` against a constant

### ~Remaining~ Previous problems

This change obviously changes the memory layout of the types. And it turns out some libraries invalidly assumes the memory layout and does very dangerous pointer casts to convert them. These libraries will have undefined behaviour and perform invalid memory access until patched.

- [x] - `mio` - Issue: https://github.com/tokio-rs/mio/issues/1386.
  - [x] `0.7` branch https://github.com/tokio-rs/mio/pull/1388
  - [x] `0.7.6` published https://github.com/tokio-rs/mio/pull/1398
  - [x] Yank all `0.7` versions older than `0.7.6`
  - [x] Report `<0.7.6` to RustSec Advisory Database https://rustsec.org/advisories/RUSTSEC-2020-0081.html
- [x] - `socket2` - Issue: https://github.com/rust-lang/socket2-rs/issues/119.
  - [x] `0.3.x` branch https://github.com/rust-lang/socket2-rs/pull/120
  - [x] `0.3.16` published
  - [x] `master` branch https://github.com/rust-lang/socket2-rs/pull/122
  - [x] Yank all `0.3` versions older than `0.3.16`
  - [x] Report `<0.3.16` to RustSec Advisory Database https://rustsec.org/advisories/RUSTSEC-2020-0079.html
- [x] - `net2` - Issue: https://github.com/deprecrated/net2-rs/issues/105
  - [x] https://github.com/deprecrated/net2-rs/pull/106
  - [x] `0.2.36` published
  - [x] Yank all `0.2` versions older than `0.2.36`
  - [x] Report `<0.2.36` to RustSec Advisory Database https://rustsec.org/advisories/RUSTSEC-2020-0078.html
- [x] - `miow` - Issue: https://github.com/yoshuawuyts/miow/issues/38
  - [x] `0.3.x` - https://github.com/yoshuawuyts/miow/pull/39
  - [x] `0.3.6` published
  - [x] `0.2.x` - https://github.com/yoshuawuyts/miow/pull/40
  - [x] `0.2.2` published
  - [x] Yanked all `0.2` versions older than `0.2.2`
  - [x] Yanked all `0.3` versions older than `0.3.6`
  - [x] Report `<0.2.2` and `<0.3.6` to RustSec Advisory Database https://rustsec.org/advisories/RUSTSEC-2020-0080.html
- [x] - `quinn master` (aka what became 0.7) - https://github.com/quinn-rs/quinn/issues/968 https://github.com/quinn-rs/quinn/pull/987
  - [x] - `quinn 0.6` - https://github.com/quinn-rs/quinn/pull/1045
  - [x] - `quinn 0.5` - https://github.com/quinn-rs/quinn/pull/1046
  - [x] - Release `0.7.0`, `0.6.2` and `0.5.4`
- [x] - `nb-connect` - https://github.com/smol-rs/nb-connect/issues/1
  - [x] - Release `1.0.3`
  - [x] - Yank all versions older than `1.0.3`
- [x] - `shadowsocks-rust` - https://github.com/shadowsocks/shadowsocks-rust/issues/462
- [ ] - `rio` - https://github.com/spacejam/rio/issues/44
- [ ] - `seaslug` - https://github.com/spacejam/seaslug/issues/1

#### Fixed crate versions

All crates I have found that assumed the memory layout have been fixed and published. The crates and versions that will continue working even as/if this PR is merged is (please upgrade these to help unblock this PR):

* `net2 0.2.36`
* `socket2 0.3.16`
* `miow 0.2.2`
* `miow 0.3.6`
* `mio 0.7.6`
* `mio 0.6.23` - Never had the invalid assumption itself, but has now been bumped to only allow fixed dependencies (`net2` + `miow`)
* `nb-connect 1.0.3`
* `quinn 0.5.4`
* `quinn 0.6.2`

### Release notes draft

This release changes the memory layout of `Ipv4Addr`, `Ipv6Addr`, `SocketAddrV4` and `SocketAddrV6`. The standard library no longer implements these as the corresponding `libc` structs (`sockaddr_in`, `sockaddr_in6` etc.). This internal representation was never exposed, but some crates relied on it anyway by unsafely transmuting. This change will cause those crates to make invalid memory accesses. Notably `net2 <0.2.36`, `socket2 <0.3.16`, `mio <0.7.6`, `miow <0.3.6` and a few other crates are affected. All known affected crates have been patched and have had fixed versions published over a year ago. If any affected crate is still in your dependency tree, you need to upgrade them before using this version of Rust.
This commit is contained in:
bors 2022-07-31 15:56:28 +00:00
commit 3405e402fa
10 changed files with 172 additions and 247 deletions

View File

@ -7,12 +7,12 @@ use crate::hash;
use crate::io::{self, Write}; use crate::io::{self, Write};
use crate::iter; use crate::iter;
use crate::mem; use crate::mem;
use crate::net::{htons, ntohs, IpAddr, Ipv4Addr, Ipv6Addr}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::option; use crate::option;
use crate::slice; use crate::slice;
use crate::sys::net::netc as c; use crate::sys::net::netc as c;
use crate::sys_common::net::LookupHost; use crate::sys_common::net::LookupHost;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{FromInner, IntoInner};
use crate::vec; use crate::vec;
/// An internet socket address, either IPv4 or IPv6. /// An internet socket address, either IPv4 or IPv6.
@ -73,12 +73,11 @@ pub enum SocketAddr {
/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
/// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.port(), 8080);
/// ``` /// ```
#[derive(Copy)] #[derive(Copy, Clone, Eq, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct SocketAddrV4 { pub struct SocketAddrV4 {
// Do not assume that this struct is implemented as the underlying system representation. ip: Ipv4Addr,
// The memory layout is not part of the stable interface that std exposes. port: u16,
inner: c::sockaddr_in,
} }
/// An IPv6 socket address. /// An IPv6 socket address.
@ -107,12 +106,13 @@ pub struct SocketAddrV4 {
/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
/// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.port(), 8080);
/// ``` /// ```
#[derive(Copy)] #[derive(Copy, Clone, Eq, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct SocketAddrV6 { pub struct SocketAddrV6 {
// Do not assume that this struct is implemented as the underlying system representation. ip: Ipv6Addr,
// The memory layout is not part of the stable interface that std exposes. port: u16,
inner: c::sockaddr_in6, flowinfo: u32,
scope_id: u32,
} }
impl SocketAddr { impl SocketAddr {
@ -131,7 +131,8 @@ impl SocketAddr {
/// ``` /// ```
#[stable(feature = "ip_addr", since = "1.7.0")] #[stable(feature = "ip_addr", since = "1.7.0")]
#[must_use] #[must_use]
pub fn new(ip: IpAddr, port: u16) -> SocketAddr { #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
match ip { match ip {
IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
@ -277,15 +278,9 @@ impl SocketAddrV4 {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[must_use] #[must_use]
pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
SocketAddrV4 { pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
inner: c::sockaddr_in { SocketAddrV4 { ip, port }
sin_family: c::AF_INET as c::sa_family_t,
sin_port: htons(port),
sin_addr: ip.into_inner(),
..unsafe { mem::zeroed() }
},
}
} }
/// Returns the IP address associated with this socket address. /// Returns the IP address associated with this socket address.
@ -302,9 +297,7 @@ impl SocketAddrV4 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv4Addr { pub const fn ip(&self) -> &Ipv4Addr {
// SAFETY: `Ipv4Addr` is `#[repr(C)] struct { _: in_addr; }`. &self.ip
// It is safe to cast from `&in_addr` to `&Ipv4Addr`.
unsafe { &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr) }
} }
/// Changes the IP address associated with this socket address. /// Changes the IP address associated with this socket address.
@ -320,7 +313,7 @@ impl SocketAddrV4 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_ip(&mut self, new_ip: Ipv4Addr) { pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
self.inner.sin_addr = new_ip.into_inner() self.ip = new_ip;
} }
/// Returns the port number associated with this socket address. /// Returns the port number associated with this socket address.
@ -337,7 +330,7 @@ impl SocketAddrV4 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 { pub const fn port(&self) -> u16 {
ntohs(self.inner.sin_port) self.port
} }
/// Changes the port number associated with this socket address. /// Changes the port number associated with this socket address.
@ -353,7 +346,7 @@ impl SocketAddrV4 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_port(&mut self, new_port: u16) { pub fn set_port(&mut self, new_port: u16) {
self.inner.sin_port = htons(new_port); self.port = new_port;
} }
} }
@ -376,17 +369,9 @@ impl SocketAddrV6 {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[must_use] #[must_use]
pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
SocketAddrV6 { pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
inner: c::sockaddr_in6 { SocketAddrV6 { ip, port, flowinfo, scope_id }
sin6_family: c::AF_INET6 as c::sa_family_t,
sin6_port: htons(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. /// Returns the IP address associated with this socket address.
@ -403,7 +388,7 @@ impl SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv6Addr { pub const fn ip(&self) -> &Ipv6Addr {
unsafe { &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr) } &self.ip
} }
/// Changes the IP address associated with this socket address. /// Changes the IP address associated with this socket address.
@ -419,7 +404,7 @@ impl SocketAddrV6 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_ip(&mut self, new_ip: Ipv6Addr) { pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
self.inner.sin6_addr = *new_ip.as_inner() self.ip = new_ip;
} }
/// Returns the port number associated with this socket address. /// Returns the port number associated with this socket address.
@ -436,7 +421,7 @@ impl SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 { pub const fn port(&self) -> u16 {
ntohs(self.inner.sin6_port) self.port
} }
/// Changes the port number associated with this socket address. /// Changes the port number associated with this socket address.
@ -452,7 +437,7 @@ impl SocketAddrV6 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_port(&mut self, new_port: u16) { pub fn set_port(&mut self, new_port: u16) {
self.inner.sin6_port = htons(new_port); self.port = new_port;
} }
/// Returns the flow information associated with this address. /// Returns the flow information associated with this address.
@ -479,7 +464,7 @@ impl SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn flowinfo(&self) -> u32 { pub const fn flowinfo(&self) -> u32 {
self.inner.sin6_flowinfo self.flowinfo
} }
/// Changes the flow information associated with this socket address. /// Changes the flow information associated with this socket address.
@ -497,7 +482,7 @@ impl SocketAddrV6 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_flowinfo(&mut self, new_flowinfo: u32) { pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
self.inner.sin6_flowinfo = new_flowinfo; self.flowinfo = new_flowinfo;
} }
/// Returns the scope ID associated with this address. /// Returns the scope ID associated with this address.
@ -519,7 +504,7 @@ impl SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn scope_id(&self) -> u32 { pub const fn scope_id(&self) -> u32 {
self.inner.sin6_scope_id self.scope_id
} }
/// Changes the scope ID associated with this socket address. /// Changes the scope ID associated with this socket address.
@ -537,19 +522,48 @@ impl SocketAddrV6 {
/// ``` /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")] #[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_scope_id(&mut self, new_scope_id: u32) { pub fn set_scope_id(&mut self, new_scope_id: u32) {
self.inner.sin6_scope_id = new_scope_id; self.scope_id = new_scope_id;
} }
} }
impl FromInner<c::sockaddr_in> for SocketAddrV4 { impl FromInner<c::sockaddr_in> for SocketAddrV4 {
fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
SocketAddrV4 { inner: addr } SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) }
} }
} }
impl FromInner<c::sockaddr_in6> for SocketAddrV6 { impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
SocketAddrV6 { inner: addr } SocketAddrV6 {
ip: Ipv6Addr::from_inner(addr.sin6_addr),
port: u16::from_be(addr.sin6_port),
flowinfo: addr.sin6_flowinfo,
scope_id: addr.sin6_scope_id,
}
}
}
impl IntoInner<c::sockaddr_in> for SocketAddrV4 {
fn into_inner(self) -> c::sockaddr_in {
c::sockaddr_in {
sin_family: c::AF_INET as c::sa_family_t,
sin_port: self.port.to_be(),
sin_addr: self.ip.into_inner(),
..unsafe { mem::zeroed() }
}
}
}
impl IntoInner<c::sockaddr_in6> for SocketAddrV6 {
fn into_inner(self) -> c::sockaddr_in6 {
c::sockaddr_in6 {
sin6_family: c::AF_INET6 as c::sa_family_t,
sin6_port: self.port.to_be(),
sin6_addr: self.ip.into_inner(),
sin6_flowinfo: self.flowinfo,
sin6_scope_id: self.scope_id,
..unsafe { mem::zeroed() }
}
} }
} }
@ -582,19 +596,6 @@ impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
} }
} }
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")] #[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for SocketAddr { impl fmt::Display for SocketAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -688,40 +689,6 @@ impl fmt::Debug for SocketAddrV6 {
} }
} }
#[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 = "socketaddr_ordering", since = "1.45.0")] #[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl PartialOrd for SocketAddrV4 { impl PartialOrd for SocketAddrV4 {
fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> { fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
@ -753,19 +720,13 @@ impl Ord for SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for SocketAddrV4 { impl hash::Hash for SocketAddrV4 {
fn hash<H: hash::Hasher>(&self, s: &mut H) { fn hash<H: hash::Hasher>(&self, s: &mut H) {
(self.inner.sin_port, self.inner.sin_addr.s_addr).hash(s) (self.port, self.ip).hash(s)
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for SocketAddrV6 { impl hash::Hash for SocketAddrV6 {
fn hash<H: hash::Hasher>(&self, s: &mut H) { fn hash<H: hash::Hasher>(&self, s: &mut H) {
( (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
self.inner.sin6_port,
&self.inner.sin6_addr.s6_addr,
self.inner.sin6_flowinfo,
self.inner.sin6_scope_id,
)
.hash(s)
} }
} }

View File

@ -4,20 +4,16 @@ mod tests;
use crate::cmp::Ordering; use crate::cmp::Ordering;
use crate::fmt::{self, Write as FmtWrite}; use crate::fmt::{self, Write as FmtWrite};
use crate::hash;
use crate::io::Write as IoWrite; use crate::io::Write as IoWrite;
use crate::mem::transmute; use crate::mem::transmute;
use crate::sys::net::netc as c; use crate::sys::net::netc as c;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{FromInner, IntoInner};
/// An IP address, either IPv4 or IPv6. /// An IP address, either IPv4 or IPv6.
/// ///
/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
/// respective documentation for more details. /// respective documentation for more details.
/// ///
/// The size of an `IpAddr` instance may vary depending on the target operating
/// system.
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@ -50,9 +46,6 @@ pub enum IpAddr {
/// ///
/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
/// ///
/// The size of an `Ipv4Addr` struct may vary depending on the target operating
/// system.
///
/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
/// ///
/// # Textual representation /// # Textual representation
@ -77,10 +70,10 @@ pub enum IpAddr {
/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal /// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex /// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
/// ``` /// ```
#[derive(Copy)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv4Addr { pub struct Ipv4Addr {
inner: c::in_addr, octets: [u8; 4],
} }
/// An IPv6 address. /// An IPv6 address.
@ -88,9 +81,6 @@ pub struct Ipv4Addr {
/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
/// They are usually represented as eight 16-bit segments. /// They are usually represented as eight 16-bit segments.
/// ///
/// The size of an `Ipv6Addr` struct may vary depending on the target operating
/// system.
///
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
/// ///
/// # Embedding IPv4 Addresses /// # Embedding IPv4 Addresses
@ -162,10 +152,10 @@ pub struct Ipv4Addr {
/// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!("::1".parse(), Ok(localhost));
/// assert_eq!(localhost.is_loopback(), true); /// assert_eq!(localhost.is_loopback(), true);
/// ``` /// ```
#[derive(Copy)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv6Addr { pub struct Ipv6Addr {
inner: c::in6_addr, octets: [u8; 16],
} }
/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. /// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
@ -461,9 +451,7 @@ impl Ipv4Addr {
#[must_use] #[must_use]
#[inline] #[inline]
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
// `s_addr` is stored as BE on all machine and the array is in BE order. Ipv4Addr { octets: [a, b, c, d] }
// So the native endian conversion method is used so that it's never swapped.
Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
} }
/// An IPv4 address with the address pointing to localhost: `127.0.0.1` /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
@ -523,8 +511,7 @@ impl Ipv4Addr {
#[must_use] #[must_use]
#[inline] #[inline]
pub const fn octets(&self) -> [u8; 4] { pub const fn octets(&self) -> [u8; 4] {
// This returns the order we want because s_addr is stored in big-endian. self.octets
self.inner.s_addr.to_ne_bytes()
} }
/// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
@ -547,7 +534,7 @@ impl Ipv4Addr {
#[must_use] #[must_use]
#[inline] #[inline]
pub const fn is_unspecified(&self) -> bool { pub const fn is_unspecified(&self) -> bool {
self.inner.s_addr == 0 u32::from_be_bytes(self.octets) == 0
} }
/// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
@ -910,9 +897,7 @@ impl Ipv4Addr {
#[inline] #[inline]
pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
let [a, b, c, d] = self.octets(); let [a, b, c, d] = self.octets();
Ipv6Addr { Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] },
}
} }
/// Converts this address to an [IPv4-mapped] [`IPv6` address]. /// Converts this address to an [IPv4-mapped] [`IPv6` address].
@ -937,9 +922,7 @@ impl Ipv4Addr {
#[inline] #[inline]
pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
let [a, b, c, d] = self.octets(); let [a, b, c, d] = self.octets();
Ipv6Addr { Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] },
}
} }
} }
@ -1034,22 +1017,6 @@ impl fmt::Debug for Ipv4Addr {
} }
} }
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for Ipv4Addr {
#[inline]
fn clone(&self) -> Ipv4Addr {
*self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for Ipv4Addr {
#[inline]
fn eq(&self, other: &Ipv4Addr) -> bool {
self.inner.s_addr == other.inner.s_addr
}
}
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<Ipv4Addr> for IpAddr { impl PartialEq<Ipv4Addr> for IpAddr {
#[inline] #[inline]
@ -1072,21 +1039,6 @@ impl PartialEq<IpAddr> for Ipv4Addr {
} }
} }
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for Ipv4Addr {}
#[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for Ipv4Addr {
#[inline]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
// NOTE:
// * hash in big endian order
// * in netbsd, `in_addr` has `repr(packed)`, we need to
// copy `s_addr` to avoid unsafe borrowing
{ self.inner.s_addr }.hash(s)
}
}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for Ipv4Addr { impl PartialOrd for Ipv4Addr {
#[inline] #[inline]
@ -1121,15 +1073,21 @@ impl PartialOrd<IpAddr> for Ipv4Addr {
impl Ord for Ipv4Addr { impl Ord for Ipv4Addr {
#[inline] #[inline]
fn cmp(&self, other: &Ipv4Addr) -> Ordering { fn cmp(&self, other: &Ipv4Addr) -> Ordering {
// Compare as native endian self.octets.cmp(&other.octets)
u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
} }
} }
impl IntoInner<c::in_addr> for Ipv4Addr { impl IntoInner<c::in_addr> for Ipv4Addr {
#[inline] #[inline]
fn into_inner(self) -> c::in_addr { fn into_inner(self) -> c::in_addr {
self.inner // `s_addr` is stored as BE on all machines and the array is in BE order.
// So the native endian conversion method is used so that it's never swapped.
c::in_addr { s_addr: u32::from_ne_bytes(self.octets) }
}
}
impl FromInner<c::in_addr> for Ipv4Addr {
fn from_inner(addr: c::in_addr) -> Ipv4Addr {
Ipv4Addr { octets: addr.s_addr.to_ne_bytes() }
} }
} }
@ -1147,8 +1105,7 @@ impl From<Ipv4Addr> for u32 {
/// ``` /// ```
#[inline] #[inline]
fn from(ip: Ipv4Addr) -> u32 { fn from(ip: Ipv4Addr) -> u32 {
let ip = ip.octets(); u32::from_be_bytes(ip.octets)
u32::from_be_bytes(ip)
} }
} }
@ -1166,7 +1123,7 @@ impl From<u32> for Ipv4Addr {
/// ``` /// ```
#[inline] #[inline]
fn from(ip: u32) -> Ipv4Addr { fn from(ip: u32) -> Ipv4Addr {
Ipv4Addr::from(ip.to_be_bytes()) Ipv4Addr { octets: ip.to_be_bytes() }
} }
} }
@ -1184,7 +1141,7 @@ impl From<[u8; 4]> for Ipv4Addr {
/// ``` /// ```
#[inline] #[inline]
fn from(octets: [u8; 4]) -> Ipv4Addr { fn from(octets: [u8; 4]) -> Ipv4Addr {
Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) Ipv4Addr { octets }
} }
} }
@ -1234,13 +1191,9 @@ impl Ipv6Addr {
h.to_be(), h.to_be(),
]; ];
Ipv6Addr { Ipv6Addr {
inner: c::in6_addr { // All elements in `addr16` are big endian.
// All elements in `addr16` are big endian. // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
// SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
// rustc_allow_const_fn_unstable: the transmute could be written as stable const
// code, but that leads to worse code generation (#75085)
s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
},
} }
} }
@ -1285,11 +1238,9 @@ impl Ipv6Addr {
#[must_use] #[must_use]
#[inline] #[inline]
pub const fn segments(&self) -> [u16; 8] { pub const fn segments(&self) -> [u16; 8] {
// All elements in `s6_addr` must be big endian. // All elements in `self.octets` must be big endian.
// SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
// rustc_allow_const_fn_unstable: the transmute could be written as stable const code, but let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
// that leads to worse code generation (#75085)
let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
// We want native endian u16 // We want native endian u16
[ [
u16::from_be(a), u16::from_be(a),
@ -1748,7 +1699,7 @@ impl Ipv6Addr {
#[must_use] #[must_use]
#[inline] #[inline]
pub const fn octets(&self) -> [u8; 16] { pub const fn octets(&self) -> [u8; 16] {
self.inner.s6_addr self.octets
} }
} }
@ -1856,22 +1807,6 @@ impl fmt::Debug for Ipv6Addr {
} }
} }
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for Ipv6Addr {
#[inline]
fn clone(&self) -> Ipv6Addr {
*self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for Ipv6Addr {
#[inline]
fn eq(&self, other: &Ipv6Addr) -> bool {
self.inner.s6_addr == other.inner.s6_addr
}
}
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<IpAddr> for Ipv6Addr { impl PartialEq<IpAddr> for Ipv6Addr {
#[inline] #[inline]
@ -1894,17 +1829,6 @@ impl PartialEq<Ipv6Addr> for IpAddr {
} }
} }
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for Ipv6Addr {}
#[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for Ipv6Addr {
#[inline]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
self.inner.s6_addr.hash(s)
}
}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for Ipv6Addr { impl PartialOrd for Ipv6Addr {
#[inline] #[inline]
@ -1943,16 +1867,15 @@ impl Ord for Ipv6Addr {
} }
} }
impl AsInner<c::in6_addr> for Ipv6Addr { impl IntoInner<c::in6_addr> for Ipv6Addr {
#[inline] fn into_inner(self) -> c::in6_addr {
fn as_inner(&self) -> &c::in6_addr { c::in6_addr { s6_addr: self.octets }
&self.inner
} }
} }
impl FromInner<c::in6_addr> for Ipv6Addr { impl FromInner<c::in6_addr> for Ipv6Addr {
#[inline] #[inline]
fn from_inner(addr: c::in6_addr) -> Ipv6Addr { fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
Ipv6Addr { inner: addr } Ipv6Addr { octets: addr.s6_addr }
} }
} }
@ -1973,8 +1896,7 @@ impl From<Ipv6Addr> for u128 {
/// ``` /// ```
#[inline] #[inline]
fn from(ip: Ipv6Addr) -> u128 { fn from(ip: Ipv6Addr) -> u128 {
let ip = ip.octets(); u128::from_be_bytes(ip.octets)
u128::from_be_bytes(ip)
} }
} }
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
@ -2025,8 +1947,7 @@ impl From<[u8; 16]> for Ipv6Addr {
/// ``` /// ```
#[inline] #[inline]
fn from(octets: [u8; 16]) -> Ipv6Addr { fn from(octets: [u8; 16]) -> Ipv6Addr {
let inner = c::in6_addr { s6_addr: octets }; Ipv6Addr { octets }
Ipv6Addr::from_inner(inner)
} }
} }

View File

@ -944,3 +944,26 @@ fn ip_const() {
const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
assert!(!IS_IP_V6); assert!(!IS_IP_V6);
} }
#[test]
fn structural_match() {
// test that all IP types can be structurally matched upon
const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
match IPV4 {
Ipv4Addr::LOCALHOST => {}
_ => unreachable!(),
}
const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
match IPV6 {
Ipv6Addr::LOCALHOST => {}
_ => unreachable!(),
}
const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
match IP {
IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
_ => unreachable!(),
}
}

View File

@ -69,15 +69,6 @@ pub enum Shutdown {
Both, Both,
} }
#[inline]
const fn htons(i: u16) -> u16 {
i.to_be()
}
#[inline]
const fn ntohs(i: u16) -> u16 {
u16::from_be(i)
}
fn each_addr<A: ToSocketAddrs, 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 where
F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>, F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>,

View File

@ -538,6 +538,4 @@ pub mod netc {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct sockaddr {} pub struct sockaddr {}
pub type socklen_t = usize;
} }

View File

@ -139,8 +139,8 @@ impl Socket {
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?; self.set_nonblocking(true)?;
let r = unsafe { let r = unsafe {
let (addrp, len) = addr.into_inner(); let (addr, len) = addr.into_inner();
cvt(libc::connect(self.as_raw_fd(), addrp, len)) cvt(libc::connect(self.as_raw_fd(), addr.as_ptr(), len))
}; };
self.set_nonblocking(false)?; self.set_nonblocking(false)?;

View File

@ -363,6 +363,4 @@ pub mod netc {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct sockaddr {} pub struct sockaddr {}
pub type socklen_t = usize;
} }

View File

@ -524,6 +524,4 @@ pub mod netc {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct sockaddr {} pub struct sockaddr {}
pub type socklen_t = usize;
} }

View File

@ -143,8 +143,8 @@ impl Socket {
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?; self.set_nonblocking(true)?;
let result = { let result = {
let (addrp, len) = addr.into_inner(); let (addr, len) = addr.into_inner();
let result = unsafe { c::connect(self.as_raw_socket(), addrp, len) }; let result = unsafe { c::connect(self.as_raw_socket(), addr.as_ptr(), len) };
cvt(result).map(drop) cvt(result).map(drop)
}; };
self.set_nonblocking(false)?; self.set_nonblocking(false)?;

View File

@ -10,7 +10,7 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::ptr; use crate::ptr;
use crate::sys::net::netc as c; use crate::sys::net::netc as c;
use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket}; use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket};
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{FromInner, IntoInner};
use crate::time::Duration; use crate::time::Duration;
use libc::{c_int, c_void}; use libc::{c_int, c_void};
@ -224,8 +224,8 @@ impl TcpStream {
let sock = Socket::new(addr, c::SOCK_STREAM)?; let sock = Socket::new(addr, c::SOCK_STREAM)?;
let (addrp, len) = addr.into_inner(); let (addr, len) = addr.into_inner();
cvt_r(|| unsafe { c::connect(sock.as_raw(), addrp, len) })?; cvt_r(|| unsafe { c::connect(sock.as_raw(), addr.as_ptr(), len) })?;
Ok(TcpStream { inner: sock }) Ok(TcpStream { inner: sock })
} }
@ -395,8 +395,8 @@ impl TcpListener {
setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
// Bind our new socket // Bind our new socket
let (addrp, len) = addr.into_inner(); let (addr, len) = addr.into_inner();
cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "horizon")] { if #[cfg(target_os = "horizon")] {
@ -500,8 +500,8 @@ impl UdpSocket {
init(); init();
let sock = Socket::new(addr, c::SOCK_DGRAM)?; let sock = Socket::new(addr, c::SOCK_DGRAM)?;
let (addrp, len) = addr.into_inner(); let (addr, len) = addr.into_inner();
cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
Ok(UdpSocket { inner: sock }) Ok(UdpSocket { inner: sock })
} }
@ -531,14 +531,14 @@ impl UdpSocket {
pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
let (dstp, dstlen) = dst.into_inner(); let (dst, dstlen) = dst.into_inner();
let ret = cvt(unsafe { let ret = cvt(unsafe {
c::sendto( c::sendto(
self.inner.as_raw(), self.inner.as_raw(),
buf.as_ptr() as *const c_void, buf.as_ptr() as *const c_void,
len, len,
MSG_NOSIGNAL, MSG_NOSIGNAL,
dstp, dst.as_ptr(),
dstlen, dstlen,
) )
})?; })?;
@ -621,7 +621,7 @@ impl UdpSocket {
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = c::ipv6_mreq { let mreq = c::ipv6_mreq {
ipv6mr_multiaddr: *multiaddr.as_inner(), ipv6mr_multiaddr: multiaddr.into_inner(),
ipv6mr_interface: to_ipv6mr_interface(interface), ipv6mr_interface: to_ipv6mr_interface(interface),
}; };
setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
@ -637,7 +637,7 @@ impl UdpSocket {
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = c::ipv6_mreq { let mreq = c::ipv6_mreq {
ipv6mr_multiaddr: *multiaddr.as_inner(), ipv6mr_multiaddr: multiaddr.into_inner(),
ipv6mr_interface: to_ipv6mr_interface(interface), ipv6mr_interface: to_ipv6mr_interface(interface),
}; };
setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
@ -677,8 +677,8 @@ impl UdpSocket {
} }
pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
let (addrp, len) = addr?.into_inner(); let (addr, len) = addr?.into_inner();
cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addrp, len) }).map(drop) cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
} }
} }
@ -700,3 +700,38 @@ impl fmt::Debug for UdpSocket {
res.field(name, &self.inner.as_raw()).finish() res.field(name, &self.inner.as_raw()).finish()
} }
} }
////////////////////////////////////////////////////////////////////////////////
// Converting SocketAddr to libc representation
////////////////////////////////////////////////////////////////////////////////
/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level
/// SocketAddr* types into their system representation. The benefit of this specific
/// type over using `c::sockaddr_storage` is that this type is exactly as large as it
/// needs to be and not a lot larger. And it can be initialized more cleanly from Rust.
#[repr(C)]
pub(crate) union SocketAddrCRepr {
v4: c::sockaddr_in,
v6: c::sockaddr_in6,
}
impl SocketAddrCRepr {
pub fn as_ptr(&self) -> *const c::sockaddr {
self as *const _ as *const c::sockaddr
}
}
impl<'a> IntoInner<(SocketAddrCRepr, c::socklen_t)> for &'a SocketAddr {
fn into_inner(self) -> (SocketAddrCRepr, c::socklen_t) {
match *self {
SocketAddr::V4(ref a) => {
let sockaddr = SocketAddrCRepr { v4: a.into_inner() };
(sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t)
}
SocketAddr::V6(ref a) => {
let sockaddr = SocketAddrCRepr { v6: a.into_inner() };
(sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t)
}
}
}
}