Skip to content

Commit f86b2f7

Browse files
committed
ffi: fix conversions between SocketAddr and strust sockaddr
Due to rust-lang/rust#78802 we can't simply copy the binary representation of `SocketAddr` into `struct sockaddr*` and vice versa, so implement proper conversions.
1 parent 34c4ada commit f86b2f7

File tree

2 files changed

+276
-44
lines changed

2 files changed

+276
-44
lines changed

quiche/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ qlog = { version = "0.8", path = "../qlog", optional = true }
6767
sfv = { version = "0.9", optional = true }
6868

6969
[target."cfg(windows)".dependencies]
70-
winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef"] }
70+
winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef", "ws2tcpip"] }
7171

7272
[dev-dependencies]
7373
mio = { version = "0.8", features = ["net", "os-poll"] }

quiche/src/ffi.rs

Lines changed: 275 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ use std::ptr;
2929
use std::slice;
3030
use std::sync::atomic;
3131

32+
use std::net::Ipv4Addr;
33+
use std::net::Ipv6Addr;
3234
use std::net::SocketAddr;
35+
use std::net::SocketAddrV4;
36+
use std::net::SocketAddrV6;
3337

3438
#[cfg(unix)]
3539
use std::os::unix::io::FromRawFd;
@@ -42,6 +46,31 @@ use libc::sockaddr;
4246
use libc::ssize_t;
4347
use libc::timespec;
4448

49+
#[cfg(not(windows))]
50+
use libc::AF_INET;
51+
#[cfg(windows)]
52+
use winapi::shared::ws2def::AF_INET;
53+
54+
#[cfg(not(windows))]
55+
use libc::AF_INET6;
56+
#[cfg(windows)]
57+
use winapi::shared::ws2def::AF_INET6;
58+
59+
#[cfg(not(windows))]
60+
use libc::in_addr;
61+
#[cfg(windows)]
62+
use winapi::shared::inaddr::IN_ADDR as in_addr;
63+
64+
#[cfg(not(windows))]
65+
use libc::in6_addr;
66+
#[cfg(windows)]
67+
use winapi::shared::in6addr::IN6_ADDR as in6_addr;
68+
69+
#[cfg(not(windows))]
70+
use libc::sa_family_t;
71+
#[cfg(windows)]
72+
use winapi::shared::ws2def::ADDRESS_FAMILY as sa_family_t;
73+
4574
#[cfg(not(windows))]
4675
use libc::sockaddr_in;
4776
#[cfg(windows)]
@@ -62,15 +91,12 @@ use libc::c_int as socklen_t;
6291
#[cfg(not(windows))]
6392
use libc::socklen_t;
6493

65-
#[cfg(not(windows))]
66-
use libc::AF_INET;
6794
#[cfg(windows)]
68-
use winapi::shared::ws2def::AF_INET;
69-
70-
#[cfg(not(windows))]
71-
use libc::AF_INET6;
95+
use winapi::shared::in6addr::in6_addr_u;
7296
#[cfg(windows)]
73-
use winapi::shared::ws2def::AF_INET6;
97+
use winapi::shared::inaddr::in_addr_S_un;
98+
#[cfg(windows)]
99+
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;
74100

75101
use crate::*;
76102

@@ -1259,54 +1285,155 @@ pub extern fn quiche_conn_send_quantum(conn: &mut Connection) -> size_t {
12591285
}
12601286

12611287
fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
1262-
unsafe {
1263-
match addr.sa_family as i32 {
1264-
AF_INET => {
1265-
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
1288+
match addr.sa_family as i32 {
1289+
AF_INET => {
1290+
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
12661291

1267-
SocketAddr::V4(
1268-
*(addr as *const _ as *const sockaddr_in as *const _),
1269-
)
1270-
},
1292+
let in4 = unsafe { *(addr as *const _ as *const sockaddr_in) };
12711293

1272-
AF_INET6 => {
1273-
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
1294+
#[cfg(not(windows))]
1295+
let ip_addr = Ipv4Addr::from(u32::from_be(in4.sin_addr.s_addr));
1296+
#[cfg(windows)]
1297+
let ip_addr = {
1298+
let ip_bytes = unsafe { in4.sin_addr.S_un.S_un_b() };
12741299

1275-
SocketAddr::V6(
1276-
*(addr as *const _ as *const sockaddr_in6 as *const _),
1277-
)
1278-
},
1300+
Ipv4Addr::from([
1301+
ip_bytes.s_b1,
1302+
ip_bytes.s_b2,
1303+
ip_bytes.s_b3,
1304+
ip_bytes.s_b4,
1305+
])
1306+
};
12791307

1280-
_ => unimplemented!("unsupported address type"),
1281-
}
1282-
}
1283-
}
1308+
let port = u16::from_be(in4.sin_port);
12841309

1285-
fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
1286-
unsafe {
1287-
match addr {
1288-
SocketAddr::V4(addr) => {
1289-
let sa_len = std::mem::size_of::<sockaddr_in>();
1310+
let out = SocketAddrV4::new(ip_addr, port);
1311+
1312+
out.into()
1313+
},
12901314

1291-
let src = addr as *const _ as *const u8;
1292-
let dst = out as *mut _ as *mut u8;
1315+
AF_INET6 => {
1316+
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
12931317

1294-
std::ptr::copy_nonoverlapping(src, dst, sa_len);
1318+
let in6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
12951319

1296-
sa_len as socklen_t
1297-
},
1320+
let ip_addr = Ipv6Addr::from(
1321+
#[cfg(not(windows))]
1322+
in6.sin6_addr.s6_addr,
1323+
#[cfg(windows)]
1324+
*unsafe { in6.sin6_addr.u.Byte() },
1325+
);
12981326

1299-
SocketAddr::V6(addr) => {
1300-
let sa_len = std::mem::size_of::<sockaddr_in6>();
1327+
let port = u16::from_be(in6.sin6_port);
13011328

1302-
let src = addr as *const _ as *const u8;
1303-
let dst = out as *mut _ as *mut u8;
1329+
#[cfg(not(windows))]
1330+
let scope_id = in6.sin6_scope_id;
1331+
#[cfg(windows)]
1332+
let scope_id = unsafe { *in6.u.sin6_scope_id() };
13041333

1305-
std::ptr::copy_nonoverlapping(src, dst, sa_len);
1334+
let out =
1335+
SocketAddrV6::new(ip_addr, port, in6.sin6_flowinfo, scope_id);
13061336

1307-
sa_len as socklen_t
1308-
},
1309-
}
1337+
out.into()
1338+
},
1339+
1340+
_ => unimplemented!("unsupported address type"),
1341+
}
1342+
}
1343+
1344+
fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
1345+
let sin_port = addr.port().to_be();
1346+
1347+
match addr {
1348+
SocketAddr::V4(addr) => unsafe {
1349+
let sa_len = std::mem::size_of::<sockaddr_in>();
1350+
let out_in = out as *mut _ as *mut sockaddr_in;
1351+
1352+
let s_addr = u32::from_ne_bytes(addr.ip().octets());
1353+
1354+
#[cfg(not(windows))]
1355+
let sin_addr = in_addr { s_addr };
1356+
#[cfg(windows)]
1357+
let sin_addr = {
1358+
let mut s_un = std::mem::zeroed::<in_addr_S_un>();
1359+
*s_un.S_addr_mut() = s_addr;
1360+
in_addr { S_un: s_un }
1361+
};
1362+
1363+
*out_in = sockaddr_in {
1364+
sin_family: AF_INET as sa_family_t,
1365+
1366+
sin_addr,
1367+
1368+
#[cfg(any(
1369+
target_os = "macos",
1370+
target_os = "ios",
1371+
target_os = "watchos",
1372+
target_os = "freebsd",
1373+
target_os = "dragonfly",
1374+
target_os = "openbsd",
1375+
target_os = "netbsd"
1376+
))]
1377+
sin_len: sa_len as u8,
1378+
1379+
sin_port,
1380+
1381+
sin_zero: std::mem::zeroed(),
1382+
};
1383+
1384+
sa_len as socklen_t
1385+
},
1386+
1387+
SocketAddr::V6(addr) => unsafe {
1388+
let sa_len = std::mem::size_of::<sockaddr_in6>();
1389+
let out_in6 = out as *mut _ as *mut sockaddr_in6;
1390+
1391+
#[cfg(not(windows))]
1392+
let sin6_addr = in6_addr {
1393+
s6_addr: addr.ip().octets(),
1394+
};
1395+
#[cfg(windows)]
1396+
let sin6_addr = {
1397+
let mut u = std::mem::zeroed::<in6_addr_u>();
1398+
*u.Byte_mut() = addr.ip().octets();
1399+
in6_addr { u }
1400+
};
1401+
1402+
#[cfg(windows)]
1403+
let u = {
1404+
let mut u = std::mem::zeroed::<SOCKADDR_IN6_LH_u>();
1405+
*u.sin6_scope_id_mut() = addr.scope_id();
1406+
u
1407+
};
1408+
1409+
*out_in6 = sockaddr_in6 {
1410+
sin6_family: AF_INET6 as sa_family_t,
1411+
1412+
sin6_addr,
1413+
1414+
#[cfg(any(
1415+
target_os = "macos",
1416+
target_os = "ios",
1417+
target_os = "watchos",
1418+
target_os = "freebsd",
1419+
target_os = "dragonfly",
1420+
target_os = "openbsd",
1421+
target_os = "netbsd"
1422+
))]
1423+
sin6_len: sa_len as u8,
1424+
1425+
sin6_port: sin_port,
1426+
1427+
sin6_flowinfo: addr.flowinfo(),
1428+
1429+
#[cfg(not(windows))]
1430+
sin6_scope_id: addr.scope_id(),
1431+
#[cfg(windows)]
1432+
u,
1433+
};
1434+
1435+
sa_len as socklen_t
1436+
},
13101437
}
13111438
}
13121439

@@ -1323,3 +1450,108 @@ fn std_time_to_c(_time: &std::time::Instant, out: &mut timespec) {
13231450
out.tv_sec = 0;
13241451
out.tv_nsec = 0;
13251452
}
1453+
1454+
#[cfg(test)]
1455+
mod tests {
1456+
use super::*;
1457+
1458+
#[cfg(windows)]
1459+
use winapi::um::ws2tcpip::inet_ntop;
1460+
1461+
#[test]
1462+
fn addr_v4() {
1463+
let addr = "127.0.0.1:8080".parse().unwrap();
1464+
1465+
let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1466+
1467+
assert_eq!(
1468+
std_addr_to_c(&addr, &mut out),
1469+
std::mem::size_of::<sockaddr_in>() as socklen_t
1470+
);
1471+
1472+
let s = std::ffi::CString::new("ddd.ddd.ddd.ddd").unwrap();
1473+
1474+
let s = unsafe {
1475+
let in_addr = &out as *const _ as *const sockaddr_in;
1476+
assert_eq!(u16::from_be((*in_addr).sin_port), addr.port());
1477+
1478+
let dst = s.into_raw();
1479+
1480+
inet_ntop(
1481+
AF_INET,
1482+
&((*in_addr).sin_addr) as *const _ as *const c_void,
1483+
dst,
1484+
16,
1485+
);
1486+
1487+
std::ffi::CString::from_raw(dst).into_string().unwrap()
1488+
};
1489+
1490+
assert_eq!(s, "127.0.0.1");
1491+
1492+
let addr = unsafe {
1493+
std_addr_from_c(
1494+
&*(&out as *const _ as *const sockaddr),
1495+
std::mem::size_of::<sockaddr_in>() as socklen_t,
1496+
)
1497+
};
1498+
1499+
assert_eq!(addr, "127.0.0.1:8080".parse().unwrap());
1500+
}
1501+
1502+
#[test]
1503+
fn addr_v6() {
1504+
let addr = "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1505+
.parse()
1506+
.unwrap();
1507+
1508+
let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1509+
1510+
assert_eq!(
1511+
std_addr_to_c(&addr, &mut out),
1512+
std::mem::size_of::<sockaddr_in6>() as socklen_t
1513+
);
1514+
1515+
let s = std::ffi::CString::new("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd")
1516+
.unwrap();
1517+
1518+
let s = unsafe {
1519+
let in6_addr = &out as *const _ as *const sockaddr_in6;
1520+
assert_eq!(u16::from_be((*in6_addr).sin6_port), addr.port());
1521+
1522+
let dst = s.into_raw();
1523+
1524+
inet_ntop(
1525+
AF_INET6,
1526+
&((*in6_addr).sin6_addr) as *const _ as *const c_void,
1527+
dst,
1528+
45,
1529+
);
1530+
1531+
std::ffi::CString::from_raw(dst).into_string().unwrap()
1532+
};
1533+
1534+
assert_eq!(s, "2001:db8:85a3::8a2e:370:7334");
1535+
1536+
let addr = unsafe {
1537+
std_addr_from_c(
1538+
&*(&out as *const _ as *const sockaddr),
1539+
std::mem::size_of::<sockaddr_in6>() as socklen_t,
1540+
)
1541+
};
1542+
1543+
assert_eq!(
1544+
addr,
1545+
"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1546+
.parse()
1547+
.unwrap()
1548+
);
1549+
}
1550+
1551+
#[cfg(not(windows))]
1552+
extern {
1553+
fn inet_ntop(
1554+
af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t,
1555+
) -> *mut c_char;
1556+
}
1557+
}

0 commit comments

Comments
 (0)