Skip to content

Commit 49b43f2

Browse files
faernpfmooney
authored andcommitted
Do not assume memory layout of std::net::SocketAddr
Fixes #105 Reviewed by: Thomas de Zeeuw <[email protected]>
1 parent 77a6eb4 commit 49b43f2

File tree

2 files changed

+124
-10
lines changed

2 files changed

+124
-10
lines changed

Diff for: src/socket.rs

+123-10
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl Socket {
3232
pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> {
3333
let (addr, len) = addr2raw(addr);
3434
unsafe {
35-
::cvt(c::bind(self.inner.raw(), addr, len as c::socklen_t)).map(|_| ())
35+
::cvt(c::bind(self.inner.raw(), addr.as_ptr(), len as c::socklen_t)).map(|_| ())
3636
}
3737
}
3838

@@ -45,7 +45,7 @@ impl Socket {
4545
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
4646
let (addr, len) = addr2raw(addr);
4747
unsafe {
48-
::cvt(c::connect(self.inner.raw(), addr, len)).map(|_| ())
48+
::cvt(c::connect(self.inner.raw(), addr.as_ptr(), len)).map(|_| ())
4949
}
5050
}
5151

@@ -84,17 +84,130 @@ impl ::IntoInner for Socket {
8484
fn into_inner(self) -> sys::Socket { self.inner }
8585
}
8686

87-
fn addr2raw(addr: &SocketAddr) -> (*const c::sockaddr, c::socklen_t) {
88-
match *addr {
89-
SocketAddr::V4(ref a) => {
90-
(a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
91-
}
92-
SocketAddr::V6(ref a) => {
93-
(a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
94-
}
87+
/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level
88+
/// SocketAddr* types into their system representation. The benefit of this specific
89+
/// type over using `c::sockaddr_storage` is that this type is exactly as large as it
90+
/// needs to be and not a lot larger.
91+
#[repr(C)]
92+
pub(crate) union SocketAddrCRepr {
93+
v4: c::sockaddr_in,
94+
v6: c::sockaddr_in6,
95+
}
96+
97+
impl SocketAddrCRepr {
98+
pub(crate) fn as_ptr(&self) -> *const c::sockaddr {
99+
self as *const _ as *const c::sockaddr
95100
}
96101
}
97102

103+
fn addr2raw(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) {
104+
match addr {
105+
&SocketAddr::V4(ref v4) => addr2raw_v4(v4),
106+
&SocketAddr::V6(ref v6) => addr2raw_v6(v6),
107+
}
108+
}
109+
110+
#[cfg(unix)]
111+
fn addr2raw_v4(addr: &SocketAddrV4) -> (SocketAddrCRepr, c::socklen_t) {
112+
let sin_addr = c::in_addr {
113+
s_addr: u32::from(*addr.ip()).to_be(),
114+
};
115+
116+
let sockaddr = SocketAddrCRepr {
117+
v4: c::sockaddr_in {
118+
sin_family: c::AF_INET as c::sa_family_t,
119+
sin_port: addr.port().to_be(),
120+
sin_addr,
121+
sin_zero: [0; 8],
122+
#[cfg(any(
123+
target_os = "dragonfly",
124+
target_os = "freebsd",
125+
target_os = "ios",
126+
target_os = "macos",
127+
target_os = "netbsd",
128+
target_os = "openbsd"
129+
))]
130+
sin_len: 0,
131+
},
132+
};
133+
(sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t)
134+
}
135+
136+
#[cfg(windows)]
137+
fn addr2raw_v4(addr: &SocketAddrV4) -> (SocketAddrCRepr, c::socklen_t) {
138+
let sin_addr = unsafe {
139+
let mut s_un = mem::zeroed::<c::in_addr_S_un>();
140+
*s_un.S_addr_mut() = u32::from(*addr.ip()).to_be();
141+
c::IN_ADDR { S_un: s_un }
142+
};
143+
144+
let sockaddr = SocketAddrCRepr {
145+
v4: c::sockaddr_in {
146+
sin_family: c::AF_INET as c::sa_family_t,
147+
sin_port: addr.port().to_be(),
148+
sin_addr,
149+
sin_zero: [0; 8],
150+
},
151+
};
152+
(sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t)
153+
}
154+
155+
#[cfg(unix)]
156+
fn addr2raw_v6(addr: &SocketAddrV6) -> (SocketAddrCRepr, c::socklen_t) {
157+
let sin6_addr = {
158+
let mut sin6_addr = unsafe { mem::zeroed::<c::in6_addr>() };
159+
sin6_addr.s6_addr = addr.ip().octets();
160+
sin6_addr
161+
};
162+
163+
let sockaddr = SocketAddrCRepr {
164+
v6: c::sockaddr_in6 {
165+
sin6_family: c::AF_INET6 as c::sa_family_t,
166+
sin6_port: addr.port().to_be(),
167+
sin6_addr,
168+
sin6_flowinfo: addr.flowinfo(),
169+
sin6_scope_id: addr.scope_id(),
170+
#[cfg(any(
171+
target_os = "dragonfly",
172+
target_os = "freebsd",
173+
target_os = "ios",
174+
target_os = "macos",
175+
target_os = "netbsd",
176+
target_os = "openbsd"
177+
))]
178+
sin6_len: 0,
179+
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
180+
__sin6_src_id: 0,
181+
},
182+
};
183+
(sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t)
184+
}
185+
186+
#[cfg(windows)]
187+
fn addr2raw_v6(addr: &SocketAddrV6) -> (SocketAddrCRepr, c::socklen_t) {
188+
let sin6_addr = unsafe {
189+
let mut u = mem::zeroed::<c::in6_addr_u>();
190+
*u.Byte_mut() = addr.ip().octets();
191+
c::IN6_ADDR { u }
192+
};
193+
let scope_id = unsafe {
194+
let mut u = mem::zeroed::<c::SOCKADDR_IN6_LH_u>();
195+
*u.sin6_scope_id_mut() = addr.scope_id();
196+
u
197+
};
198+
199+
let sockaddr = SocketAddrCRepr {
200+
v6: c::sockaddr_in6 {
201+
sin6_family: c::AF_INET6 as c::sa_family_t,
202+
sin6_port: addr.port().to_be(),
203+
sin6_addr,
204+
sin6_flowinfo: addr.flowinfo(),
205+
u: scope_id,
206+
},
207+
};
208+
(sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t)
209+
}
210+
98211
fn raw2addr(storage: &c::sockaddr_storage, len: c::socklen_t) -> io::Result<SocketAddr> {
99212
match storage.ss_family as c_int {
100213
c::AF_INET => {

Diff for: src/sys/windows/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub mod c {
3434
pub use winapi::shared::ws2def::SOCKADDR as sockaddr;
3535
pub use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage;
3636
pub use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in;
37+
pub use winapi::shared::ws2def::ADDRESS_FAMILY as sa_family_t;
3738
pub use winapi::shared::ws2ipdef::*;
3839
pub use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
3940
pub use winapi::shared::ws2ipdef::IP_MREQ as ip_mreq;

0 commit comments

Comments
 (0)