//! `sys/socket.h` implementation. //! //! See . use core::{mem, ptr}; use crate::{ error::ResultExt, header::{bits_safamily_t::sa_family_t, sys_uio::iovec}, platform::{ PalSocket, Sys, types::{c_char, c_int, c_long, c_uchar, c_uint, c_void, size_t, ssize_t}, }, }; pub use crate::header::bits_socklen_t::socklen_t; pub mod constants; /// See . #[repr(C)] #[derive(Default, CheckVsLibcCrate)] pub struct linger { /// Indicates whether linger option is enabled. pub l_onoff: c_int, /// Linger time, in seconds. pub l_linger: c_int, } /// See . #[repr(C)] #[derive(Debug, CheckVsLibcCrate)] pub struct msghdr { /// Optional address. pub msg_name: *mut c_void, /// Size of address. pub msg_namelen: socklen_t, /// Scatter/gather array. pub msg_iov: *mut iovec, /// Members in `msg_iov`. pub msg_iovlen: size_t, /// Ancilliary data. pub msg_control: *mut c_void, /// Ancilliary data buffer length. pub msg_controllen: size_t, /// Flags on received message. pub msg_flags: c_int, } /// See . #[repr(C)] #[derive(Debug, CheckVsLibcCrate)] pub struct cmsghdr { /// Data byte count, including the `cmsghdr`. pub cmsg_len: size_t, /// Originating protocol. pub cmsg_level: c_int, /// Protocol-specific type. pub cmsg_type: c_int, } /// See . #[repr(C)] #[derive(Default, CheckVsLibcCrate)] pub struct sockaddr { /// Address family. pub sa_family: sa_family_t, /// Socket address. pub sa_data: [c_char; 14], } // Max size of [`sockaddr_storage`] /// cbindgen:ignore const _SS_MAXSIZE: usize = 128; // Align to pointer width /// cbindgen:ignore const _SS_PADDING: usize = _SS_MAXSIZE - mem::size_of::() - mem::size_of::(); /// See . /// Opaque storage large enough to hold any protocol specific address structure. /// /// ## Implementation notes /// * The total size of this struct is 128 bytes which is based off of `musl` and `glibc` /// * The underscore fields are implementation specific details for padding that may change /// * [`usize`] is used because it's the width of a pointer for a given platform /// * The order of the fields is important because the bytes in the padding will be cast to and /// from protocol structs in C /// /// cbindgen:ignore #[repr(C)] //#[derive(CheckVsLibcCrate)] FIXME: can't ignore private fields yet pub struct sockaddr_storage { /// Address family. pub ss_family: sa_family_t, __ss_pad2: [u8; _SS_PADDING], __ss_align: usize, } // These must match C macros in sys_socket/cbindgen.toml { /// cbindgen:ignore pub unsafe extern "C" fn __CMSG_LEN(cmsg: *const cmsghdr) -> ssize_t { ((unsafe { (*cmsg).cmsg_len as size_t } + mem::size_of::() - 1) & !(mem::size_of::() - 1)) as ssize_t } /// cbindgen:ignore pub unsafe extern "C" fn __CMSG_NEXT(cmsg: *const cmsghdr) -> *mut c_uchar { unsafe { (cmsg as *mut c_uchar).offset(__CMSG_LEN(cmsg)) } } /// cbindgen:ignore pub unsafe extern "C" fn __MHDR_END(mhdr: *const msghdr) -> *mut c_uchar { unsafe { ((*mhdr).msg_control.cast::()).add((*mhdr).msg_controllen) } } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { unsafe { (cmsg as *mut c_uchar).add(CMSG_ALIGN(mem::size_of::())) } } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { if cmsg.is_null() { return unsafe { CMSG_FIRSTHDR(mhdr) }; }; unsafe { let next = cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len) + CMSG_ALIGN(mem::size_of::()); let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen; if next > max { ptr::null_mut::() } else { (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len)) as *mut cmsghdr } } } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { unsafe { if (*mhdr).msg_controllen >= mem::size_of::() { (*mhdr).msg_control.cast::() } else { ptr::null_mut::() } } } #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_ALIGN(len: size_t) -> size_t { (len + mem::size_of::() - 1) & !(mem::size_of::() - 1) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_SPACE(len: c_uint) -> c_uint { (unsafe { CMSG_ALIGN(len as size_t) } + unsafe { CMSG_ALIGN(mem::size_of::()) }) as c_uint } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn CMSG_LEN(length: c_uint) -> c_uint { (unsafe { CMSG_ALIGN(mem::size_of::()) } + length as usize) as c_uint } // } These must match C macros in sys_socket/cbindgen.toml /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn accept( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::accept(socket, address, address_len) }.or_minus_one_errno(), "accept({}, {:p}, {:p})", socket, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn bind( socket: c_int, address: *const sockaddr, address_len: socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::bind(socket, address, address_len) } .map(|()| 0) .or_minus_one_errno(), "bind({}, {:p}, {})", socket, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn connect( socket: c_int, address: *const sockaddr, address_len: socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::connect(socket, address, address_len) }.or_minus_one_errno(), "connect({}, {:p}, {})", socket, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn getpeername( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::getpeername(socket, address, address_len) } .map(|()| 0) .or_minus_one_errno(), "getpeername({}, {:p}, {:p})", socket, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn getsockname( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::getsockname(socket, address, address_len) } .map(|()| 0) .or_minus_one_errno(), "getsockname({}, {:p}, {:p})", socket, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn getsockopt( socket: c_int, level: c_int, option_name: c_int, option_value: *mut c_void, option_len: *mut socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::getsockopt(socket, level, option_name, option_value, option_len) } .map(|()| 0) .or_minus_one_errno(), "getsockopt({}, {}, {}, {:p}, {:p})", socket, level, option_name, option_value, option_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn listen(socket: c_int, backlog: c_int) -> c_int { Sys::listen(socket, backlog) .map(|()| 0) .or_minus_one_errno() } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn recv( socket: c_int, buffer: *mut c_void, length: size_t, flags: c_int, ) -> ssize_t { unsafe { recvfrom( socket, buffer, length, flags, ptr::null_mut(), ptr::null_mut(), ) } } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn recvfrom( socket: c_int, buffer: *mut c_void, length: size_t, flags: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> ssize_t { trace_expr!( unsafe { Sys::recvfrom(socket, buffer, length, flags, address, address_len) } .map(|r| r as ssize_t) .or_minus_one_errno(), "recvfrom({}, {:p}, {}, {:#x}, {:p}, {:p})", socket, buffer, length, flags, address, address_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn recvmsg(socket: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t { unsafe { Sys::recvmsg(socket, msg, flags) } .map(|r| r as ssize_t) .or_minus_one_errno() } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn send( socket: c_int, message: *const c_void, length: size_t, flags: c_int, ) -> ssize_t { unsafe { sendto(socket, message, length, flags, ptr::null(), 0) } } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sendmsg(socket: c_int, msg: *const msghdr, flags: c_int) -> ssize_t { unsafe { Sys::sendmsg(socket, msg, flags) } .map(|w| w as ssize_t) .or_minus_one_errno() } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sendto( socket: c_int, message: *const c_void, length: size_t, flags: c_int, dest_addr: *const sockaddr, dest_len: socklen_t, ) -> ssize_t { trace_expr!( unsafe { Sys::sendto(socket, message, length, flags, dest_addr, dest_len) } .map(|w| w as ssize_t) .or_minus_one_errno(), "sendto({}, {:p}, {}, {:#x}, {:p}, {})", socket, message, length, flags, dest_addr, dest_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn setsockopt( socket: c_int, level: c_int, option_name: c_int, option_value: *const c_void, option_len: socklen_t, ) -> c_int { trace_expr!( unsafe { Sys::setsockopt(socket, level, option_name, option_value, option_len) } .map(|()| 0) .or_minus_one_errno(), "setsockopt({}, {}, {}, {:p}, {})", socket, level, option_name, option_value, option_len ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn shutdown(socket: c_int, how: c_int) -> c_int { Sys::shutdown(socket, how).map(|()| 0).or_minus_one_errno() } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int { trace_expr!( unsafe { Sys::socket(domain, kind, protocol) }.or_minus_one_errno(), "socket({}, {}, {})", domain, kind, protocol, ) } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn socketpair( domain: c_int, kind: c_int, protocol: c_int, sv: *mut c_int, ) -> c_int { trace_expr!( Sys::socketpair(domain, kind, protocol, unsafe { &mut *sv.cast::<[c_int; 2]>() }) .map(|()| 0) .or_minus_one_errno(), "socketpair({}, {}, {}, {:p})", domain, kind, protocol, sv ) }