socket2 Rust Documentation

repository·master·Indexed 21 days ago

https://github.com/rust-lang/socket2

A low-level utility crate for Rust providing access to advanced socket configuration options not present in the standard library. It maps closely to system calls without using unsafe code, offering direct access to system socket functionality for users familiar with libc or low-level socket programming. Supports Linux, macOS, and Windows as Tier 1 platforms, with a minimum supported Rust version of 1.70.0.

Tokens
7.4K
Snippets
19
Records
38
Agent score
74%

What's inside socket2

  1. Overview of Socket2

    master

    Socket2 is a Rust crate designed to provide utilities for creating and using sockets with advanced configuration options that are unavailable in the Rust standard library.

    Key Characteristics:

    • Direct System Access: It provides as direct as possible access to system socket functionality, meaning it offers maximal flexibility but minimal cross-platform abstraction.
    • No Unsafe Code: The crate aims to provide these advanced options without requiring the user to write unsafe code.
    • Low-Level Design: Most functions map directly to equivalent system calls. Because of this, the crate does not apply high-level error handling (e.g., it does not automatically handle EINTR).

    Warning: This crate is intended for users who already understand how to create and manage sockets using libc or system calls. If you are unfamiliar with low-level socket programming, this crate may be too complex for your needs.

  2. Use `SockRef` to configure standard library sockets

    master

    The SockRef type provides a way to use the advanced configuration methods of the socket2::Socket API on socket types owned by other libraries, such as std::net::TcpStream or std::net::TcpListener.

    Because SockRef is a reference, it does not take ownership of the underlying socket. It uses ManuallyDrop internally to ensure that when the SockRef is dropped, the underlying socket is not closed, allowing the original owner (e.g., the TcpStream) to continue using it.

    Platform Support

    • Unix/WASI: Works with any type implementing std::os::fd::AsFd.
    • Windows: Works with any type implementing std::os::windows::io::AsSocket.

    Usage Pattern

    1. Create a socket using the standard library (e.g., TcpStream::connect).
    2. Create a SockRef using SockRef::from(&socket).
    3. Call socket2 methods (like set_tcp_nodelay) via the SockRef instance.
    4. The SockRef implements Deref, so it behaves like a Socket reference.
    use std::net::{TcpStream, SocketAddr};
    use socket2::SockRef;
    
    // Create `TcpStream` from the standard library.
    let address: SocketAddr = "127.0.0.1:1234".parse().unwrap();
    let stream = TcpStream::connect(address).unwrap();
    
    // Create a `SockRef`erence to the stream.
    let socket_ref = SockRef::from(&stream);
    
    // Use `Socket` methods on the standard library stream via the reference.
    socket_ref.set_tcp_nodelay(true).unwrap();
    
    // The original stream is still valid and reflects the changes.
    assert_eq!(stream.nodelay().unwrap(), true);
  3. Use the Socket type for advanced socket configuration

    master

    The Socket type is an owned wrapper around a system socket (a file descriptor on Unix or a SOCKET on Windows). It is the primary type in socket2 and is designed to mirror raw OS socket semantics closely.

    Key Capabilities:

    • Creation: Create sockets with specific Domain, Type, and Protocol using Socket::new (which sets common flags like close-on-exec) or Socket::new_raw (for no automatic configuration).
    • Conversion: You can convert a Socket into standard library network primitives like std::net::TcpStream or std::net::UdpSocket using the From trait.
    • Lifecycle: Manage connections via bind, connect, listen, and accept. It also supports connect_timeout for establishing connections with a specific duration.
    • I/O: Perform low-level I/O operations including recv, send, recv_from, send_to, and vectored I/O (recv_vectored, send_vectored).
    • Non-blocking mode: Toggle between blocking and non-blocking modes using set_nonblocking.
    use std::net::{SocketAddr, TcpListener};
    use socket2::{Socket, Domain, Type};
    
    // create a TCP listener
    let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
    
    let address: SocketAddr = "[::1]:12345".parse().unwrap();
    let address = address.into();
    socket.bind(&address)?;
    socket.listen(128)?;
    
    let listener: TcpListener = socket.into();
  4. Create and configure a socket with `Socket`

    master

    The Socket type provides direct access to system socket functionality. You can create a new socket using Socket::new by specifying a Domain, Type, and an optional Protocol. Once created, you can configure advanced options (like TCP keepalive or binding to specific addresses) and eventually convert the Socket into standard library types like TcpListener or TcpStream using into().

    Note: This crate provides minimal error handling (it does not handle EINTR) and is intended for users who understand system calls.

    use std::net::{SocketAddr, TcpListener};
    use socket2::{Socket, Domain, Type};
    
    // Create a TCP listener bound to two addresses.
    let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
    
    socket.set_only_v6(false)?;
    let address: SocketAddr = "[::1]:12345".parse().unwrap();
    socket.bind(&address.into())?;
    socket.listen(128)?;
    
    let listener: TcpListener = socket.into();
  5. Check OS and Architecture Support

    master

    Socket2 supports various operating systems, categorized into Tier 1 and Tier 2 support levels.

    Tier 1 (Fully Tested)

    These platforms are tested with every commit in CI. All functions and types (excluding those behind the all feature) are guaranteed to work here:

    • Linux
    • macOS
    • Windows

    Tier 2 (Built but not tested)

    These platforms are built in CI but are not actively tested. Some functions or types may not work on these platforms, even if they are not behind the all feature flag:

    • Android
    • FreeBSD
    • Fuchsia
    • iOS
    • illumos
    • NetBSD
    • Redox
    • Solaris
    • OpenHarmony
  6. Create a pair of connected sockets

    master

    On Unix-like systems, you can create a pair of connected sockets using Socket::pair or Socket::pair_raw. Socket::pair applies common flags, while Socket::pair_raw does not.

    Signatures:

    • pub fn pair(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<(Socket, Socket)> (Unix only)
    • pub fn pair_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<(Socket, Socket)> (Unix only)
  7. Manage IPv6 Multicast Groups

    master

    Control IPv6 multicast membership.

    • Join Group: join_multicast_v6(multiaddr: &Ipv6Addr, interface: u32) joins a group using an interface index. Use 0 for any interface.
    • Leave Group: leave_multicast_v6(multiaddr: &Ipv6Addr, interface: u32).
    • Multicast Hops: set_multicast_hops_v6(hops: u32) sets the number of routers multicast packets will transit. Default is 1.
    let group = Ipv6Addr::new(0xff02, ::1, 0, 0);
    socket.join_multicast_v6(&group, 0)?;
  8. Use `MaybeUninitSlice` for uninitialized buffers

    master

    The MaybeUninitSlice<'a> type is a wrapper around [MaybeUninit<u8>] that allows you to pass uninitialized memory to system calls like recvmsg safely.

    Use MaybeUninitSlice::new(buf: &mut [MaybeUninit<u8>]) to wrap an existing slice of uninitialized bytes.

  9. Configure `recvmsg(2)` with `MsgHdrMut`

    master

    The MsgHdrMut struct is used to configure the arguments for a recvmsg(2) system call. It wraps msghdr on Unix and WSAMSG on Windows.

    Use the following methods to build the header:

    • MsgHdrMut::new(): Creates an empty header.
    • .with_addr(&mut SockAddr): Sets the mutable address buffer.
    • .with_buffers(&mut [MaybeUninitSlice]): Sets the mutable data buffers.
    • .with_control(&mut [MaybeUninit<u8>]): Sets the mutable control buffer.

    After receiving data, you can inspect the result using:

    • .flags() -> RecvFlags: Returns flags for the incoming message (e.g., check if truncated via RecvFlags::is_truncated()).
    • .control_len() -> usize: Returns the length of the control buffer filled by the system call.
  10. Manage IPv4 Multicast Groups

    master

    Control IPv4 multicast membership.

    • Join Group: join_multicast_v4(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) joins a group on a specific interface. If interface is Ipv4Addr::UNSPECIFIED, the system chooses an appropriate interface.
    • Leave Group: leave_multicast_v4(multiaddr: &Ipv4Addr, interface: &Ipv4Addr).
    • Join SSM (Source-Specific Multicast): join_ssm_v4(source: &Ipv4Addr, group: &Ipv4Addr, interface: &Ipv4Addr) joins a channel for a specific sender.
    • Leave SSM: leave_ssm_v4(source: &Ipv4Addr, group: &Ipv4Addr, interface: &Ipv4Addr).
    • Multicast Interface: set_multicast_if_v4(interface: &Ipv4Addr) sets the interface used for routing multicast packets.
    let group = Ipv4Addr::new(224, 0, 0, 1);
    let interface = Ipv4Addr::new(0, 0, 0, 0);
    socket.join_multicast_v4(&group, &interface)?;
  11. Specify the communication domain with `Domain`

    master

    The Domain type specifies the communication domain for a socket (e.g., IPv4, IPv6, or Unix). It is a newtype wrapper around a system integer.

    Available constants:

    • Domain::IPV4: IPv4 communication (AF_INET).
    • Domain::IPV6: IPv6 communication (AF_INET6).
    • Domain::UNIX: Unix socket communication (AF_UNIX) (not available on WASI).

    You can also use Domain::for_address(address: SocketAddr) to automatically determine the correct domain for a given SocketAddr.