Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  windows.rs

  Sprache: Rust
 

// Copyright 2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cmp::min;
use std::io::{self, IoSlice};
use std::marker::PhantomData;
use std::mem::{self, size_of, MaybeUninit};
use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown};
use std::os::windows::io::{
    AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
};
use std::path::Path;
use std::sync::Once;
use std::time::{Duration, Instant};
use std::{process, ptr, slice};

use windows_sys::Win32::Foundation::{SetHandleInformation, HANDLE, HANDLE_FLAG_INHERIT};
#[cfg(feature = "all")]
use windows_sys::Win32::Networking::WinSock::SO_PROTOCOL_INFOW;
use windows_sys::Win32::Networking::WinSock::{
    self, tcp_keepalive, FIONBIO, IN6_ADDR, IN6_ADDR_0, INVALID_SOCKET, IN_ADDR, IN_ADDR_0,
    POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND, SIO_KEEPALIVE_VALS,
    SOCKET_ERROR, WSABUF, WSAEMSGSIZE, WSAESHUTDOWN, WSAPOLLFD, WSAPROTOCOL_INFOW,
    WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED,
};
use windows_sys::Win32::System::Threading::INFINITE;

use crate::{MsgHdr, RecvFlags, SockAddr, TcpKeepalive, Type};

#[allow(non_camel_case_types)]
pub(cratetype c_int = std::os::raw::c_int;

/// Fake MSG_TRUNC flag for the [`RecvFlags`] struct.
///
/// The flag is enabled when a `WSARecv[From]` call returns `WSAEMSGSIZE`. The
/// value of the flag is defined by us.
pub(crateconst MSG_TRUNC: c_int = 0x01;

// Used in `Domain`.
pub(crateconst AF_INET: c_int = windows_sys::Win32::Networking::WinSock::AF_INET as c_int;
pub(crateconst AF_INET6: c_int = windows_sys::Win32::Networking::WinSock::AF_INET6 as c_int;
pub(crateconst AF_UNIX: c_int = windows_sys::Win32::Networking::WinSock::AF_UNIX as c_int;
pub(crateconst AF_UNSPEC: c_int = windows_sys::Win32::Networking::WinSock::AF_UNSPEas c_int;
// Used in `Type`.
pub(crateconst SOCK_STREAM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_STREAM as c_int;
pub(crateconst SOCK_DGRAM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_DGRAM as c_int;
pub(crateconst SOCK_RAW: c_int = windows_sys::Win32::Networking::WinSock::SOCK_RAW as c_int;
const SOCK_RDM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_RDM as c_int;
pub(crateconst SOCK_SEQPACKET: c_int =
    windows_sys::Win32::Networking::WinSock::SOCK_SEQPACKET as c_int;
// Used in `Protocol`.
pub(crateuse windows_sys::Win32::Networking::WinSock::{
    IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP,
};
// Used in `SockAddr`.
pub(crateuse windows_sys::Win32::Networking::WinSock::{
    SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_IN6 as sockaddr_in6,
    SOCKADDR_STORAGE as sockaddr_storage,
};
#[allow(non_camel_case_types)]
pub(cratetype sa_family_t = windows_sys::Win32::Networking::WinSock::ADDRESS_FAMILY;
#[allow(non_camel_case_types)]
pub(cratetype socklen_t = windows_sys::Win32::Networking::WinSock::socklen_t;
// Used in `Socket`.
#[cfg(feature = "all")]
pub(crateuse windows_sys::Win32::Networking::WinSock::IP_HDRINCL;
pub(crateuse windows_sys::Win32::Networking::WinSock::{
    IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MREQ as Ipv6Mreq,
    IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_RECVTCLASS,
    IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP,
    IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_MREQ as IpMreq,
    IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
    IP_RECVTOS, IP_TOS, IP_TTL, LINGER as linger, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR,
    SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
    SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
};
pub(crateconst IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int;
pub(crateconst SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int;

/// Type used in set/getsockopt to retrieve the `TCP_NODELAY` option.
///
/// NOTE: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt>
/// documents that options such as `TCP_NODELAY` and `SO_KEEPALIVE` expect a
/// `BOOL` (alias for `c_int`, 4 bytes), however in practice this turns out to
/// be false (or misleading) as a `BOOLEAN` (`c_uchar`, 1 byte) is returned by
/// `getsockopt`.
pub(cratetype Bool = windows_sys::Win32::Foundation::BOOLEAN;

/// Maximum size of a buffer passed to system call like `recv` and `send`.
const MAX_BUF_LEN: usize = c_int::MAX as usize;

/// Helper macro to execute a system call that returns an `io::Result`.
macro_rules! syscall {
    ($fn: ident ( $($arg: expr),* $(,)* ), $err_test: path, $err_value: expr) => {{
        #[allow(unused_unsafe)]
        let res = unsafe { windows_sys::Win32::Networking::WinSock::$fn($($arg, )*) };
        if $err_test(&res, &$err_value) {
            Err(io::Error::last_os_error())
        } else {
            Ok(res)
        }
    }};
}

impl_debug!(
    crate::Domain,
    self::AF_INET,
    self::AF_INET6,
    self::AF_UNIX,
    self::AF_UNSPEC,
);

/// Windows only API.
impl Type {
    /// Our custom flag to set `WSA_FLAG_NO_HANDLE_INHERIT` on socket creation.
    /// Trying to mimic `Type::cloexec` on windows.
    const NO_INHERIT: c_int = 1 << ((size_of::<c_int>() * 8) - 1); // Last bit.

    /// Set `WSA_FLAG_NO_HANDLE_INHERIT` on the socket.
    #[cfg(feature = "all")]
    #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
    pub const fn no_inherit(self) -> Type {
        self._no_inherit()
    }

    pub(crateconst fn _no_inherit(self) -> Type {
        Type(self.0 | Type::NO_INHERIT)
    }
}

impl_debug!(
    crate::Type,
    self::SOCK_STREAM,
    self::SOCK_DGRAM,
    self::SOCK_RAW,
    self::SOCK_RDM,
    self::SOCK_SEQPACKET,
);

impl_debug!(
    crate::Protocol,
    WinSock::IPPROTO_ICMP,
    WinSock::IPPROTO_ICMPV6,
    WinSock::IPPROTO_TCP,
    WinSock::IPPROTO_UDP,
);

impl std::fmt::Debug for RecvFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("RecvFlags")
            .field("is_truncated", &self.is_truncated())
            .finish()
    }
}

#[repr(transparent)]
pub struct MaybeUninitSlice<'a> {
    vec: WSABUF,
    _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
}

unsafe impl<'a> Send for MaybeUninitSlice<'a> {}

unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}

impl<'a> MaybeUninitSlice<'a> {
    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
        assert!(buf.len() <= u32::MAX as usize);
        MaybeUninitSlice {
            vec: WSABUF {
                len: buf.len() as u32,
                buf: buf.as_mut_ptr().cast(),
            },
            _lifetime: PhantomData,
        }
    }

    pub fn as_slice(&self) -> &[MaybeUninit<u8>] {
        unsafe { slice::from_raw_parts(self.vec.buf.cast(), self.vec.len as usize) }
    }

    pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
        unsafe { slice::from_raw_parts_mut(self.vec.buf.cast(), self.vec.len as usize) }
    }
}

// Used in `MsgHdr`.
pub(crateuse windows_sys::Win32::Networking::WinSock::WSAMSG as msghdr;

pub(cratefn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
    msg.name = name.as_ptr() as *mut _;
    msg.namelen = name.len();
}

pub(cratefn set_msghdr_iov(msg: &mut msghdr, ptr: *mut WSABUF, len: usize) {
    msg.lpBuffers = ptr;
    msg.dwBufferCount = min(len, u32::MAX as usize) as u32;
}

pub(cratefn set_msghdr_control(msg: &mut msghdr, ptr: *mut u8, len: usize) {
    msg.Control.buf = ptr;
    msg.Control.len = len as u32;
}

pub(cratefn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
    msg.dwFlags = flags as u32;
}

pub(cratefn msghdr_flags(msg: &msghdr) -> RecvFlags {
    RecvFlags(msg.dwFlags as c_int)
}

pub(cratefn msghdr_control_len(msg: &msghdr) -> usize {
    msg.Control.len as _
}

fn init() {
    static INIT: Once = Once::new();

    INIT.call_once(|| {
        // Initialize winsock through the standard library by just creating a
        // dummy socket. Whether this is successful or not we drop the result as
        // libstd will be sure to have initialized winsock.
        let _ = net::UdpSocket::bind("127.0.0.1:34254");
    });
}

pub(cratetype Socket = windows_sys::Win32::Networking::WinSock::SOCKET;

pub(crateunsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
    crate::socket::Inner::from_raw_socket(socket as RawSocket)
}

pub(cratefn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
    socket.as_raw_socket() as Socket
}

pub(cratefn socket_into_raw(socket: crate::socket::Inner) -> Socket {
    socket.into_raw_socket() as Socket
}

pub(cratefn socket(family: c_int, mut ty: c_int, protocol: c_int) -> io::Result<Socket> {
    init();

    // Check if we set our custom flag.
    let flags = if ty & Type::NO_INHERIT != 0 {
        ty = ty & !Type::NO_INHERIT;
        WSA_FLAG_NO_HANDLE_INHERIT
    } else {
        0
    };

    syscall!(
        WSASocketW(
            family,
            ty,
            protocol,
            ptr::null_mut(),
            0,
            WSA_FLAG_OVERLAPPED | flags,
        ),
        PartialEq::eq,
        INVALID_SOCKET
    )
}

pub(cratefn bind(socket: Socket, addr: &SockAddr) -> io::Result<()> {
    syscall!(bind(socket, addr.as_ptr(), addr.len()), PartialEq::ne, 0).map(|_| ())
}

pub(cratefn connect(socket: Socket, addr: &SockAddr) -> io::Result<()> {
    syscall!(connect(socket, addr.as_ptr(), addr.len()), PartialEq::ne, 0).map(|_| ())
}

pub(cratefn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
    let start = Instant::now();

    let mut fd_array = WSAPOLLFD {
        fd: socket.as_raw(),
        events: (POLLRDNORM | POLLWRNORM) as i16,
        revents: 0,
    };

    loop {
        let elapsed = start.elapsed();
        if elapsed >= timeout {
            return Err(io::ErrorKind::TimedOut.into());
        }

        let timeout = (timeout - elapsed).as_millis();
        let timeout = clamp(timeout, 1, c_int::MAX as u128) as c_int;

        match syscall!(
            WSAPoll(&mut fd_array, 1, timeout),
            PartialEq::eq,
            SOCKET_ERROR
        ) {
            Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
            Ok(_) => {
                // Error or hang up indicates an error (or failure to connect).
                if (fd_array.revents & POLLERR as i16) != 0
                    || (fd_array.revents & POLLHUP as i16) != 0
                {
                    match socket.take_error() {
                        Ok(Some(err)) => return Err(err),
                        Ok(None) => {
                            return Err(io::Error::new(
                                io::ErrorKind::Other,
                                "no error set after POLLHUP",
                            ))
                        }
                        Err(err) => return Err(err),
                    }
                }
                return Ok(());
            }
            // Got interrupted, try again.
            Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
            Err(err) => return Err(err),
        }
    }
}

// TODO: use clamp from std lib, stable since 1.50.
fn clamp<T>(value: T, min: T, max: T) -> T
where
    T: Ord,
{
    if value <= min {
        min
    } else if value >= max {
        max
    } else {
        value
    }
}

pub(cratefn listen(socket: Socket, backlog: c_int) -> io::Result<()> {
    syscall!(listen(socket, backlog), PartialEq::ne, 0).map(|_| ())
}

pub(cratefn accept(socket: Socket) -> io::Result<(Socket, SockAddr)> {
    // Safety: `accept` initialises the `SockAddr` for us.
    unsafe {
        SockAddr::try_init(|storage, len| {
            syscall!(
                accept(socket, storage.cast(), len),
                PartialEq::eq,
                INVALID_SOCKET
            )
        })
    }
}

pub(cratefn getsockname(socket: Socket) -> io::Result<SockAddr> {
    // Safety: `getsockname` initialises the `SockAddr` for us.
    unsafe {
        SockAddr::try_init(|storage, len| {
            syscall!(
                getsockname(socket, storage.cast(), len),
                PartialEq::eq,
                SOCKET_ERROR
            )
        })
    }
    .map(|(_, addr)| addr)
}

pub(cratefn getpeername(socket: Socket) -> io::Result<SockAddr> {
    // Safety: `getpeername` initialises the `SockAddr` for us.
    unsafe {
        SockAddr::try_init(|storage, len| {
            syscall!(
                getpeername(socket, storage.cast(), len),
                PartialEq::eq,
                SOCKET_ERROR
            )
        })
    }
    .map(|(_, addr)| addr)
}

pub(cratefn try_clone(socket: Socket) -> io::Result<Socket> {
    let mut info: MaybeUninit<WSAPROTOCOL_INFOW> = MaybeUninit::uninit();
    syscall!(
        // NOTE: `process.id` is the same as `GetCurrentProcessId`.
        WSADuplicateSocketW(socket, process::id(), info.as_mut_ptr()),
        PartialEq::eq,
        SOCKET_ERROR
    )?;
    // Safety: `WSADuplicateSocketW` intialised `info` for us.
    let mut info = unsafe { info.assume_init() };

    syscall!(
        WSASocketW(
            info.iAddressFamily,
            info.iSocketType,
            info.iProtocol,
            &mut info,
            0,
            WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
        ),
        PartialEq::eq,
        INVALID_SOCKET
    )
}

pub(cratefn set_nonblocking(socket: Socket, nonblocking: bool) -> io::Result<()> {
    let mut nonblocking = if nonblocking { 1 } else { 0 };
    ioctlsocket(socket, FIONBIO, &mut nonblocking)
}

pub(cratefn shutdown(socket: Socket, how: Shutdown) -> io::Result<()> {
    let how = match how {
        Shutdown::Write => SD_SEND,
        Shutdown::Read => SD_RECEIVE,
        Shutdown::Both => SD_BOTH,
    } as i32;
    syscall!(shutdown(socket, how), PartialEq::eq, SOCKET_ERROR).map(|_| ())
}

pub(cratefn recv(socket: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
    let res = syscall!(
        recv(
            socket,
            buf.as_mut_ptr().cast(),
            min(buf.len(), MAX_BUF_LEN) as c_int,
            flags,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    );
    match res {
        Ok(n) => Ok(n as usize),
        Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok(0),
        Err(err) => Err(err),
    }
}

pub(cratefn recv_vectored(
    socket: Socket,
    bufs: &mut [crate::MaybeUninitSlice<'_>],
    flags: c_int,
) -> io::Result<(usize, RecvFlags)> {
    let mut nread = 0;
    let mut flags = flags as u32;
    let res = syscall!(
        WSARecv(
            socket,
            bufs.as_mut_ptr().cast(),
            min(bufs.len(), u32::MAX as usize) as u32,
            &mut nread,
            &mut flags,
            ptr::null_mut(),
            None,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    );
    match res {
        Ok(_) => Ok((nread as usize, RecvFlags(0))),
        Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok((0, RecvFlags(0))),
        Err(ref err) if err.raw_os_error() == Some(WSAEMSGSIZE as i32) => {
            Ok((nread as usize, RecvFlags(MSG_TRUNC)))
        }
        Err(err) => Err(err),
    }
}

pub(cratefn recv_from(
    socket: Socket,
    buf: &mut [MaybeUninit<u8>],
    flags: c_int,
) -> io::Result<(usize, SockAddr)> {
    // Safety: `recvfrom` initialises the `SockAddr` for us.
    unsafe {
        SockAddr::try_init(|storage, addrlen| {
            let res = syscall!(
                recvfrom(
                    socket,
                    buf.as_mut_ptr().cast(),
                    min(buf.len(), MAX_BUF_LEN) as c_int,
                    flags,
                    storage.cast(),
                    addrlen,
                ),
                PartialEq::eq,
                SOCKET_ERROR
            );
            match res {
                Ok(n) => Ok(n as usize),
                Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok(0),
                Err(err) => Err(err),
            }
        })
    }
}

pub(cratefn peek_sender(socket: Socket) -> io::Result<SockAddr> {
    // Safety: `recvfrom` initialises the `SockAddr` for us.
    let ((), sender) = unsafe {
        SockAddr::try_init(|storage, addrlen| {
            let res = syscall!(
                recvfrom(
                    socket,
                    // Windows *appears* not to care if you pass a null pointer.
                    ptr::null_mut(),
                    0,
                    MSG_PEEK,
                    storage.cast(),
                    addrlen,
                ),
                PartialEq::eq,
                SOCKET_ERROR
            );
            match res {
                Ok(_n) => Ok(()),
                Err(e) => match e.raw_os_error() {
                    Some(code) if code == (WSAESHUTDOWN as i32) || code == (WSAEMSGSIZE as i32) => {
                        Ok(())
                    }
                    _ => Err(e),
                },
            }
        })
    }?;

    Ok(sender)
}

pub(cratefn recv_from_vectored(
    socket: Socket,
    bufs: &mut [crate::MaybeUninitSlice<'_>],
    flags: c_int,
) -> io::Result<(usize, RecvFlags, SockAddr)> {
    // Safety: `recvfrom` initialises the `SockAddr` for us.
    unsafe {
        SockAddr::try_init(|storage, addrlen| {
            let mut nread = 0;
            let mut flags = flags as u32;
            let res = syscall!(
                WSARecvFrom(
                    socket,
                    bufs.as_mut_ptr().cast(),
                    min(bufs.len(), u32::MAX as usize) as u32,
                    &mut nread,
                    &mut flags,
                    storage.cast(),
                    addrlen,
                    ptr::null_mut(),
                    None,
                ),
                PartialEq::eq,
                SOCKET_ERROR
            );
            match res {
                Ok(_) => Ok((nread as usize, RecvFlags(0))),
                Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => {
                    Ok((nread as usize, RecvFlags(0)))
                }
                Err(ref err) if err.raw_os_error() == Some(WSAEMSGSIZE as i32) => {
                    Ok((nread as usize, RecvFlags(MSG_TRUNC)))
                }
                Err(err) => Err(err),
            }
        })
    }
    .map(|((n, recv_flags), addr)| (n, recv_flags, addr))
}

pub(cratefn send(socket: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
    syscall!(
        send(
            socket,
            buf.as_ptr().cast(),
            min(buf.len(), MAX_BUF_LEN) as c_int,
            flags,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|n| n as usize)
}

pub(cratefn send_vectored(
    socket: Socket,
    bufs: &[IoSlice<'_>],
    flags: c_int,
) -> io::Result<usize> {
    let mut nsent = 0;
    syscall!(
        WSASend(
            socket,
            // FIXME: From the `WSASend` docs [1]:
            // > For a Winsock application, once the WSASend function is called,
            // > the system owns these buffers and the application may not
            // > access them.
            //
            // So what we're doing is actually UB as `bufs` needs to be `&mut
            // [IoSlice<'_>]`.
            //
            // Tracking issue: https://github.com/rust-lang/socket2-rs/issues/129.
            //
            // NOTE: `send_to_vectored` has the same problem.
            //
            // [1] https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasend
            bufs.as_ptr() as *mut _,
            min(bufs.len(), u32::MAX as usize) as u32,
            &mut nsent,
            flags as u32,
            std::ptr::null_mut(),
            None,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| nsent as usize)
}

pub(cratefn send_to(
    socket: Socket,
    buf: &[u8],
    addr: &SockAddr,
    flags: c_int,
) -> io::Result<usize> {
    syscall!(
        sendto(
            socket,
            buf.as_ptr().cast(),
            min(buf.len(), MAX_BUF_LEN) as c_int,
            flags,
            addr.as_ptr(),
            addr.len(),
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|n| n as usize)
}

pub(cratefn send_to_vectored(
    socket: Socket,
    bufs: &[IoSlice<'_>],
    addr: &SockAddr,
    flags: c_int,
) -> io::Result<usize> {
    let mut nsent = 0;
    syscall!(
        WSASendTo(
            socket,
            // FIXME: Same problem as in `send_vectored`.
            bufs.as_ptr() as *mut _,
            bufs.len().min(u32::MAX as usize) as u32,
            &mut nsent,
            flags as u32,
            addr.as_ptr(),
            addr.len(),
            ptr::null_mut(),
            None,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| nsent as usize)
}

pub(cratefn sendmsg(socket: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
    let mut nsent = 0;
    syscall!(
        WSASendMsg(
            socket,
            &msg.inner,
            flags as u32,
            &mut nsent,
            ptr::null_mut(),
            None,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| nsent as usize)
}

/// Wrapper around `getsockopt` to deal with platform specific timeouts.
pub(cratefn timeout_opt(fd: Socket, lvl: c_int, name: i32) -> io::Result<Option<Duration>> {
    unsafe { getsockopt(fd, lvl, name).map(from_ms) }
}

fn from_ms(duration: u32) -> Option<Duration> {
    if duration == 0 {
        None
    } else {
        let secs = duration / 1000;
        let nsec = (duration % 1000) * 1000000;
        Some(Duration::new(secs as u64, nsec as u32))
    }
}

/// Wrapper around `setsockopt` to deal with platform specific timeouts.
pub(cratefn set_timeout_opt(
    socket: Socket,
    level: c_int,
    optname: i32,
    duration: Option<Duration>,
) -> io::Result<()> {
    let duration = into_ms(duration);
    unsafe { setsockopt(socket, level, optname, duration) }
}

fn into_ms(duration: Option<Duration>) -> u32 {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to
    //   INFINITE (never time out).
    duration.map_or(0, |duration| {
        min(duration.as_millis(), INFINITE as u128) as u32
    })
}

pub(cratefn set_tcp_keepalive(socket: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
    let mut keepalive = tcp_keepalive {
        onoff: 1,
        keepalivetime: into_ms(keepalive.time),
        keepaliveinterval: into_ms(keepalive.interval),
    };
    let mut out = 0;
    syscall!(
        WSAIoctl(
            socket,
            SIO_KEEPALIVE_VALS,
            &mut keepalive as *mut _ as *mut _,
            size_of::<tcp_keepalive>() as _,
            ptr::null_mut(),
            0,
            &mut out,
            ptr::null_mut(),
            None,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| ())
}

/// Caller must ensure `T` is the correct type for `level` and `optname`.
// NOTE: `optname` is actually `i32`, but all constants are `u32`.
pub(crateunsafe fn getsockopt<T>(socket: Socket, level: c_int, optname: i32) -> io::Result<T> {
    let mut optval: MaybeUninit<T> = MaybeUninit::uninit();
    let mut optlen = mem::size_of::<T>() as c_int;
    syscall!(
        getsockopt(
            socket,
            level as i32,
            optname,
            optval.as_mut_ptr().cast(),
            &mut optlen,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| {
        debug_assert_eq!(optlen as usize, mem::size_of::<T>());
        // Safety: `getsockopt` initialised `optval` for us.
        optval.assume_init()
    })
}

/// Caller must ensure `T` is the correct type for `level` and `optname`.
// NOTE: `optname` is actually `i32`, but all constants are `u32`.
pub(crateunsafe fn setsockopt<T>(
    socket: Socket,
    level: c_int,
    optname: i32,
    optval: T,
) -> io::Result<()> {
    syscall!(
        setsockopt(
            socket,
            level as i32,
            optname,
            (&optval as *const T).cast(),
            mem::size_of::<T>() as c_int,
        ),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| ())
}

fn ioctlsocket(socket: Socket, cmd: i32, payload: &mut u32) -> io::Result<()> {
    syscall!(
        ioctlsocket(socket, cmd, payload),
        PartialEq::eq,
        SOCKET_ERROR
    )
    .map(|_| ())
}

pub(cratefn to_in_addr(addr: &Ipv4Addr) -> IN_ADDR {
    IN_ADDR {
        S_un: IN_ADDR_0 {
            // `S_un` is stored as BE on all machines, and the array is in BE
            // order. So the native endian conversion method is used so that
            // it's never swapped.
            S_addr: u32::from_ne_bytes(addr.octets()),
        },
    }
}

pub(cratefn from_in_addr(in_addr: IN_ADDR) -> Ipv4Addr {
    Ipv4Addr::from(unsafe { in_addr.S_un.S_addr }.to_ne_bytes())
}

pub(cratefn to_in6_addr(addr: &Ipv6Addr) -> IN6_ADDR {
    IN6_ADDR {
        u: IN6_ADDR_0 {
            Byte: addr.octets(),
        },
    }
}

pub(cratefn from_in6_addr(addr: IN6_ADDR) -> Ipv6Addr {
    Ipv6Addr::from(unsafe { addr.u.Byte })
}

pub(cratefn to_mreqn(
    multiaddr: &Ipv4Addr,
    interface: &crate::socket::InterfaceIndexOrAddress,
) -> IpMreq {
    IpMreq {
        imr_multiaddr: to_in_addr(multiaddr),
        // Per https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ip_mreq#members:
        //
        // imr_interface
        //
        // The local IPv4 address of the interface or the interface index on
        // which the multicast group should be joined or dropped. This value is
        // in network byte order. If this member specifies an IPv4 address of
        // 0.0.0.0, the default IPv4 multicast interface is used.
        //
        // To use an interface index of 1 would be the same as an IP address of
        // 0.0.0.1.
        imr_interface: match interface {
            crate::socket::InterfaceIndexOrAddress::Index(interface) => {
                to_in_addr(&(*interface).into())
            }
            crate::socket::InterfaceIndexOrAddress::Address(interface) => to_in_addr(interface),
        },
    }
}

#[allow(unsafe_op_in_unsafe_fn)]
pub(cratefn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
    // SAFETY: a `sockaddr_storage` of all zeros is valid.
    let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
    let len = {
        let storage: &mut windows_sys::Win32::Networking::WinSock::SOCKADDR_UN =
            unsafe { &mut *(&mut storage as *mut sockaddr_storage).cast() };

        // Windows expects a UTF-8 path here even though Windows paths are
        // usually UCS-2 encoded. If Rust exposed OsStr's Wtf8 encoded
        // buffer, this could be used directly, relying on Windows to
        // validate the path, but Rust hides this implementation detail.
        //
        // See <https://github.com/rust-lang/rust/pull/95290>.
        let bytes = path
            .to_str()
            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "path must be valid UTF-8"))?
            .as_bytes();

        // Windows appears to allow non-null-terminated paths, but this is
        // not documented, so do not rely on it yet.
        //
        // See <https://github.com/rust-lang/socket2/issues/331>.
        if bytes.len() >= storage.sun_path.len() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path must be shorter than SUN_LEN",
            ));
        }

        storage.sun_family = crate::sys::AF_UNIX as sa_family_t;
        // `storage` was initialized to zero above, so the path is
        // already null terminated.
        storage.sun_path[..bytes.len()].copy_from_slice(bytes);

        let base = storage as *const _ as usize;
        let path = &storage.sun_path as *const _ as usize;
        let sun_path_offset = path - base;
        sun_path_offset + bytes.len() + 1
    };
    Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
}

/// Windows only API.
impl crate::Socket {
    /// Sets `HANDLE_FLAG_INHERIT` using `SetHandleInformation`.
    #[cfg(feature = "all")]
    #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
    pub fn set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
        self._set_no_inherit(no_inherit)
    }

    pub(cratefn _set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
        // NOTE: can't use `syscall!` because it expects the function in the
        // `windows_sys::Win32::Networking::WinSock::` path.
        let res = unsafe {
            SetHandleInformation(
                self.as_raw() as HANDLE,
                HANDLE_FLAG_INHERIT,
                !no_inherit as _,
            )
        };
        if res == 0 {
            // Zero means error.
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }

    /// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL_INFOW`
    /// option on this socket.
    ///
    /// [`Protocol`]: crate::Protocol
    #[cfg(feature = "all")]
    pub fn protocol(&self) -> io::Result<Option<crate::Protocol>> {
        let info = unsafe {
            getsockopt::<WSAPROTOCOL_INFOW>(self.as_raw(), SOL_SOCKET, SO_PROTOCOL_INFOW)?
        };
        match info.iProtocol {
            0 => Ok(None),
            p => Ok(Some(crate::Protocol::from(p))),
        }
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl AsSocket for crate::Socket {
    fn as_socket(&self) -> BorrowedSocket<'_> {
        // SAFETY: lifetime is bound by self.
        unsafe { BorrowedSocket::borrow_raw(self.as_raw() as RawSocket) }
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl AsRawSocket for crate::Socket {
    fn as_raw_socket(&self) -> RawSocket {
        self.as_raw() as RawSocket
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl From<crate::Socket> for OwnedSocket {
    fn from(sock: crate::Socket) -> OwnedSocket {
        // SAFETY: sock.into_raw() always returns a valid fd.
        unsafe { OwnedSocket::from_raw_socket(sock.into_raw() as RawSocket) }
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl IntoRawSocket for crate::Socket {
    fn into_raw_socket(self) -> RawSocket {
        self.into_raw() as RawSocket
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl From<OwnedSocket> for crate::Socket {
    fn from(fd: OwnedSocket) -> crate::Socket {
        // SAFETY: `OwnedFd` ensures the fd is valid.
        unsafe { crate::Socket::from_raw_socket(fd.into_raw_socket()) }
    }
}

#[cfg_attr(docsrs, doc(cfg(windows)))]
impl FromRawSocket for crate::Socket {
    unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket {
        crate::Socket::from_raw(socket as Socket)
    }
}

#[test]
fn in_addr_convertion() {
    let ip = Ipv4Addr::new(127001);
    let raw = to_in_addr(&ip);
    assert_eq!(unsafe { raw.S_un.S_addr }, 127 << 0 | 1 << 24);
    assert_eq!(from_in_addr(raw), ip);

    let ip = Ipv4Addr::new(12734412);
    let raw = to_in_addr(&ip);
    assert_eq!(
        unsafe { raw.S_un.S_addr },
        127 << 0 | 34 << 8 | 4 << 16 | 12 << 24
    );
    assert_eq!(from_in_addr(raw), ip);
}

#[test]
fn in6_addr_convertion() {
    let ip = Ipv6Addr::new(0x2000, 1234567);
    let raw = to_in6_addr(&ip);
    let want = [
        0x2000u16.to_be(),
        1u16.to_be(),
        2u16.to_be(),
        3u16.to_be(),
        4u16.to_be(),
        5u16.to_be(),
        6u16.to_be(),
        7u16.to_be(),
    ];
    assert_eq!(unsafe { raw.u.Word }, want);
    assert_eq!(from_in6_addr(raw), ip);
}

Messung V0.5 in Prozent
C=89 H=90 G=89

¤ Dauer der Verarbeitung: 0.33 Sekunden  (vorverarbeitet am  2026-06-18) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik