Skip to main content

bun_cares_sys/
lib.rs

1#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
2#![warn(unused_must_use)]
3
4#[path = "c_ares.rs"]
5pub mod c_ares_draft;
6
7/// Winsock typedefs not provided by `libc` on `x86_64-pc-windows-msvc`.
8#[cfg(windows)]
9pub mod winsock {
10    use core::ffi::{c_int, c_long};
11    pub(crate) type socklen_t = c_int; // ws2tcpip.h: `typedef int socklen_t;`
12    // Same nominal type as `bun_sys::posix::sockaddr*`; sin_addr is `in_addr{s_addr}`
13    // (vs the previous `[u8;4]`) but the only caller (c_ares.rs `get_sockaddr`)
14    // takes `&raw mut → cast<c_void>`, so the field's nominal type is transparent.
15    pub(crate) use bun_libuv_sys::{sockaddr, sockaddr_in, sockaddr_in6};
16    #[repr(C)]
17    #[derive(Clone, Copy)]
18    pub struct timeval {
19        pub tv_sec: c_long,
20        pub tv_usec: c_long,
21    }
22    /// c-ares' `ares.h` defines its own POSIX-layout `struct iovec { void *iov_base; size_t iov_len; }`
23    /// on Windows for the `asendv` socket-function callback — it does NOT use `WSABUF`.
24    #[repr(C)]
25    #[derive(Clone, Copy)]
26    pub struct iovec {
27        pub iov_base: *mut core::ffi::c_void,
28        pub iov_len: usize,
29    }
30}
31
32/// The full c-ares FFI module. The temporary inline scaffold that previously
33/// duplicated `ares_socklen_t` / `AddrInfo_hints` / `ares_inet_*` here has been
34/// collapsed to a re-export of the canonical `c_ares.rs` module now that it is
35/// un-gated. `c_ares` and `c_ares_draft` resolve to the SAME module, so the two
36/// `AddrInfo_hints` definitions are now nominally identical (previously a latent
37/// type-mismatch footgun for callers mixing the two paths).
38pub use c_ares_draft as c_ares;
39
40// Crate-root re-exports for callers that reference `bun_cares_sys::ares_inet_*`
41// directly (e.g. `bun_boringssl`).
42pub use c_ares::{ares_inet_ntop, ares_inet_pton};
43
44/// Thin wrapper over `ares_inet_ntop`: writes the textual address into `dst`
45/// and returns the slice up to (excluding) the trailing NUL on success.
46/// `dst[len] == 0` is guaranteed on `Some`, so callers needing a C string can
47/// rely on it.
48///
49/// # Safety
50/// `src` must point to a valid `in_addr` (af == AF_INET) or `in6_addr`
51/// (af == AF_INET6).
52#[inline]
53pub unsafe fn ntop(
54    af: core::ffi::c_int,
55    src: *const core::ffi::c_void,
56    dst: &mut [u8],
57) -> Option<&[u8]> {
58    // SAFETY: caller contract guarantees `src` points to a valid `in_addr` /
59    // `in6_addr` matching `af`; `dst` is a Rust slice so `dst.as_mut_ptr()` is
60    // valid for `dst.len()` writes, and `ares_inet_ntop` writes at most `size`
61    // bytes (including the trailing NUL) per c-ares docs.
62    if unsafe {
63        c_ares::ares_inet_ntop(
64            af,
65            src,
66            dst.as_mut_ptr(),
67            dst.len() as c_ares::ares_socklen_t,
68        )
69    }
70    .is_null()
71    {
72        return None;
73    }
74    Some(bun_core::ffi::slice_to_nul(dst))
75}