Skip to main content

relibc/header/sys_socket/
mod.rs

1//! `sys/socket.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
4
5use core::{mem, ptr};
6
7use crate::{
8    error::ResultExt,
9    header::{bits_safamily_t::sa_family_t, sys_uio::iovec},
10    platform::{
11        PalSocket, Sys,
12        types::{c_char, c_int, c_long, c_uchar, c_uint, c_void, size_t, ssize_t},
13    },
14};
15
16pub use crate::header::bits_socklen_t::socklen_t;
17
18pub mod constants;
19
20/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
21#[repr(C)]
22#[derive(Default, CheckVsLibcCrate)]
23pub struct linger {
24    /// Indicates whether linger option is enabled.
25    pub l_onoff: c_int,
26    /// Linger time, in seconds.
27    pub l_linger: c_int,
28}
29
30/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
31#[repr(C)]
32#[derive(Debug, CheckVsLibcCrate)]
33pub struct msghdr {
34    /// Optional address.
35    pub msg_name: *mut c_void,
36    /// Size of address.
37    pub msg_namelen: socklen_t,
38    /// Scatter/gather array.
39    pub msg_iov: *mut iovec,
40    /// Members in `msg_iov`.
41    pub msg_iovlen: size_t,
42    /// Ancilliary data.
43    pub msg_control: *mut c_void,
44    /// Ancilliary data buffer length.
45    pub msg_controllen: size_t,
46    /// Flags on received message.
47    pub msg_flags: c_int,
48}
49
50/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
51#[repr(C)]
52#[derive(Debug, CheckVsLibcCrate)]
53pub struct cmsghdr {
54    /// Data byte count, including the `cmsghdr`.
55    pub cmsg_len: size_t,
56    /// Originating protocol.
57    pub cmsg_level: c_int,
58    /// Protocol-specific type.
59    pub cmsg_type: c_int,
60}
61
62/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
63#[repr(C)]
64#[derive(Default, CheckVsLibcCrate)]
65pub struct sockaddr {
66    /// Address family.
67    pub sa_family: sa_family_t,
68    /// Socket address.
69    pub sa_data: [c_char; 14],
70}
71
72// Max size of [`sockaddr_storage`]
73/// cbindgen:ignore
74const _SS_MAXSIZE: usize = 128;
75// Align to pointer width
76/// cbindgen:ignore
77const _SS_PADDING: usize = _SS_MAXSIZE - mem::size_of::<sa_family_t>() - mem::size_of::<usize>();
78
79/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
80/// Opaque storage large enough to hold any protocol specific address structure.
81///
82/// ## Implementation notes
83/// * The total size of this struct is 128 bytes which is based off of `musl` and `glibc`
84/// * The underscore fields are implementation specific details for padding that may change
85/// * [`usize`] is used because it's the width of a pointer for a given platform
86/// * The order of the fields is important because the bytes in the padding will be cast to and
87///   from protocol structs in C
88///
89/// cbindgen:ignore
90#[repr(C)]
91//#[derive(CheckVsLibcCrate)] FIXME: can't ignore private fields yet
92pub struct sockaddr_storage {
93    /// Address family.
94    pub ss_family: sa_family_t,
95    __ss_pad2: [u8; _SS_PADDING],
96    __ss_align: usize,
97}
98
99// These must match C macros in sys_socket/cbindgen.toml {
100/// cbindgen:ignore
101pub unsafe extern "C" fn __CMSG_LEN(cmsg: *const cmsghdr) -> ssize_t {
102    ((unsafe { (*cmsg).cmsg_len as size_t } + mem::size_of::<c_long>() - 1)
103        & !(mem::size_of::<c_long>() - 1)) as ssize_t
104}
105
106/// cbindgen:ignore
107pub unsafe extern "C" fn __CMSG_NEXT(cmsg: *const cmsghdr) -> *mut c_uchar {
108    unsafe { (cmsg as *mut c_uchar).offset(__CMSG_LEN(cmsg)) }
109}
110
111/// cbindgen:ignore
112pub unsafe extern "C" fn __MHDR_END(mhdr: *const msghdr) -> *mut c_uchar {
113    unsafe { ((*mhdr).msg_control.cast::<c_uchar>()).add((*mhdr).msg_controllen) }
114}
115
116/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
117#[unsafe(no_mangle)]
118pub unsafe extern "C" fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar {
119    unsafe { (cmsg as *mut c_uchar).add(CMSG_ALIGN(mem::size_of::<cmsghdr>())) }
120}
121
122/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
123#[unsafe(no_mangle)]
124pub unsafe extern "C" fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr {
125    if cmsg.is_null() {
126        return unsafe { CMSG_FIRSTHDR(mhdr) };
127    };
128
129    unsafe {
130        let next =
131            cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len) + CMSG_ALIGN(mem::size_of::<cmsghdr>());
132        let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen;
133        if next > max {
134            ptr::null_mut::<cmsghdr>()
135        } else {
136            (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len)) as *mut cmsghdr
137        }
138    }
139}
140
141/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
142#[unsafe(no_mangle)]
143pub unsafe extern "C" fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr {
144    unsafe {
145        if (*mhdr).msg_controllen >= mem::size_of::<cmsghdr>() {
146            (*mhdr).msg_control.cast::<cmsghdr>()
147        } else {
148            ptr::null_mut::<cmsghdr>()
149        }
150    }
151}
152
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn CMSG_ALIGN(len: size_t) -> size_t {
155    (len + mem::size_of::<size_t>() - 1) & !(mem::size_of::<size_t>() - 1)
156}
157
158/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
159#[unsafe(no_mangle)]
160pub unsafe extern "C" fn CMSG_SPACE(len: c_uint) -> c_uint {
161    (unsafe { CMSG_ALIGN(len as size_t) } + unsafe { CMSG_ALIGN(mem::size_of::<cmsghdr>()) })
162        as c_uint
163}
164
165/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html>.
166#[unsafe(no_mangle)]
167pub unsafe extern "C" fn CMSG_LEN(length: c_uint) -> c_uint {
168    (unsafe { CMSG_ALIGN(mem::size_of::<cmsghdr>()) } + length as usize) as c_uint
169}
170// } These must match C macros in sys_socket/cbindgen.toml
171
172/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/accept.html>.
173#[unsafe(no_mangle)]
174pub unsafe extern "C" fn accept(
175    socket: c_int,
176    address: *mut sockaddr,
177    address_len: *mut socklen_t,
178) -> c_int {
179    trace_expr!(
180        unsafe { Sys::accept(socket, address, address_len) }.or_minus_one_errno(),
181        "accept({}, {:p}, {:p})",
182        socket,
183        address,
184        address_len
185    )
186}
187
188/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/bind.html>.
189#[unsafe(no_mangle)]
190pub unsafe extern "C" fn bind(
191    socket: c_int,
192    address: *const sockaddr,
193    address_len: socklen_t,
194) -> c_int {
195    trace_expr!(
196        unsafe { Sys::bind(socket, address, address_len) }
197            .map(|()| 0)
198            .or_minus_one_errno(),
199        "bind({}, {:p}, {})",
200        socket,
201        address,
202        address_len
203    )
204}
205
206/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/connect.html>.
207#[unsafe(no_mangle)]
208pub unsafe extern "C" fn connect(
209    socket: c_int,
210    address: *const sockaddr,
211    address_len: socklen_t,
212) -> c_int {
213    trace_expr!(
214        unsafe { Sys::connect(socket, address, address_len) }.or_minus_one_errno(),
215        "connect({}, {:p}, {})",
216        socket,
217        address,
218        address_len
219    )
220}
221
222/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getpeername.html>.
223#[unsafe(no_mangle)]
224pub unsafe extern "C" fn getpeername(
225    socket: c_int,
226    address: *mut sockaddr,
227    address_len: *mut socklen_t,
228) -> c_int {
229    trace_expr!(
230        unsafe { Sys::getpeername(socket, address, address_len) }
231            .map(|()| 0)
232            .or_minus_one_errno(),
233        "getpeername({}, {:p}, {:p})",
234        socket,
235        address,
236        address_len
237    )
238}
239
240/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsockname.html>.
241#[unsafe(no_mangle)]
242pub unsafe extern "C" fn getsockname(
243    socket: c_int,
244    address: *mut sockaddr,
245    address_len: *mut socklen_t,
246) -> c_int {
247    trace_expr!(
248        unsafe { Sys::getsockname(socket, address, address_len) }
249            .map(|()| 0)
250            .or_minus_one_errno(),
251        "getsockname({}, {:p}, {:p})",
252        socket,
253        address,
254        address_len
255    )
256}
257
258/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsockopt.html>.
259#[unsafe(no_mangle)]
260pub unsafe extern "C" fn getsockopt(
261    socket: c_int,
262    level: c_int,
263    option_name: c_int,
264    option_value: *mut c_void,
265    option_len: *mut socklen_t,
266) -> c_int {
267    trace_expr!(
268        unsafe { Sys::getsockopt(socket, level, option_name, option_value, option_len) }
269            .map(|()| 0)
270            .or_minus_one_errno(),
271        "getsockopt({}, {}, {}, {:p}, {:p})",
272        socket,
273        level,
274        option_name,
275        option_value,
276        option_len
277    )
278}
279
280/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/listen.html>.
281#[unsafe(no_mangle)]
282pub unsafe extern "C" fn listen(socket: c_int, backlog: c_int) -> c_int {
283    Sys::listen(socket, backlog)
284        .map(|()| 0)
285        .or_minus_one_errno()
286}
287
288/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/recv.html>.
289#[unsafe(no_mangle)]
290pub unsafe extern "C" fn recv(
291    socket: c_int,
292    buffer: *mut c_void,
293    length: size_t,
294    flags: c_int,
295) -> ssize_t {
296    unsafe {
297        recvfrom(
298            socket,
299            buffer,
300            length,
301            flags,
302            ptr::null_mut(),
303            ptr::null_mut(),
304        )
305    }
306}
307
308/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvfrom.html>.
309#[unsafe(no_mangle)]
310pub unsafe extern "C" fn recvfrom(
311    socket: c_int,
312    buffer: *mut c_void,
313    length: size_t,
314    flags: c_int,
315    address: *mut sockaddr,
316    address_len: *mut socklen_t,
317) -> ssize_t {
318    trace_expr!(
319        unsafe { Sys::recvfrom(socket, buffer, length, flags, address, address_len) }
320            .map(|r| r as ssize_t)
321            .or_minus_one_errno(),
322        "recvfrom({}, {:p}, {}, {:#x}, {:p}, {:p})",
323        socket,
324        buffer,
325        length,
326        flags,
327        address,
328        address_len
329    )
330}
331
332/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvmsg.html>.
333#[unsafe(no_mangle)]
334pub unsafe extern "C" fn recvmsg(socket: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t {
335    unsafe { Sys::recvmsg(socket, msg, flags) }
336        .map(|r| r as ssize_t)
337        .or_minus_one_errno()
338}
339
340/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/send.html>.
341#[unsafe(no_mangle)]
342pub unsafe extern "C" fn send(
343    socket: c_int,
344    message: *const c_void,
345    length: size_t,
346    flags: c_int,
347) -> ssize_t {
348    unsafe { sendto(socket, message, length, flags, ptr::null(), 0) }
349}
350
351/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html>.
352#[unsafe(no_mangle)]
353pub unsafe extern "C" fn sendmsg(socket: c_int, msg: *const msghdr, flags: c_int) -> ssize_t {
354    unsafe { Sys::sendmsg(socket, msg, flags) }
355        .map(|w| w as ssize_t)
356        .or_minus_one_errno()
357}
358
359/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html>.
360#[unsafe(no_mangle)]
361pub unsafe extern "C" fn sendto(
362    socket: c_int,
363    message: *const c_void,
364    length: size_t,
365    flags: c_int,
366    dest_addr: *const sockaddr,
367    dest_len: socklen_t,
368) -> ssize_t {
369    trace_expr!(
370        unsafe { Sys::sendto(socket, message, length, flags, dest_addr, dest_len) }
371            .map(|w| w as ssize_t)
372            .or_minus_one_errno(),
373        "sendto({}, {:p}, {}, {:#x}, {:p}, {})",
374        socket,
375        message,
376        length,
377        flags,
378        dest_addr,
379        dest_len
380    )
381}
382
383/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setsockopt.html>.
384#[unsafe(no_mangle)]
385pub unsafe extern "C" fn setsockopt(
386    socket: c_int,
387    level: c_int,
388    option_name: c_int,
389    option_value: *const c_void,
390    option_len: socklen_t,
391) -> c_int {
392    trace_expr!(
393        unsafe { Sys::setsockopt(socket, level, option_name, option_value, option_len) }
394            .map(|()| 0)
395            .or_minus_one_errno(),
396        "setsockopt({}, {}, {}, {:p}, {})",
397        socket,
398        level,
399        option_name,
400        option_value,
401        option_len
402    )
403}
404
405/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/shutdown.html>.
406#[unsafe(no_mangle)]
407pub unsafe extern "C" fn shutdown(socket: c_int, how: c_int) -> c_int {
408    Sys::shutdown(socket, how).map(|()| 0).or_minus_one_errno()
409}
410
411/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/socket.html>.
412#[unsafe(no_mangle)]
413pub unsafe extern "C" fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int {
414    trace_expr!(
415        unsafe { Sys::socket(domain, kind, protocol) }.or_minus_one_errno(),
416        "socket({}, {}, {})",
417        domain,
418        kind,
419        protocol,
420    )
421}
422
423/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/socketpair.html>.
424#[unsafe(no_mangle)]
425pub unsafe extern "C" fn socketpair(
426    domain: c_int,
427    kind: c_int,
428    protocol: c_int,
429    sv: *mut c_int,
430) -> c_int {
431    trace_expr!(
432        Sys::socketpair(domain, kind, protocol, unsafe {
433            &mut *sv.cast::<[c_int; 2]>()
434        })
435        .map(|()| 0)
436        .or_minus_one_errno(),
437        "socketpair({}, {}, {}, {:p})",
438        domain,
439        kind,
440        protocol,
441        sv
442    )
443}