Repository: tokio-rs/tokio
File: tokio/tests/io_async_fd.rs (Rust)

Code before:

    // Enable IP_RECVERR option to receive error messages
    // https://man7.org/linux/man-pages/man7/ip.7.html has some extra information
    let recv_err: libc::c_int = 1;
    unsafe {
        let res = libc::setsockopt(
            socket.as_raw_fd(),
            libc::SOL_IP,
            libc::IP_RECVERR,
            &recv_err as *const _ as *const libc::c_void,
            std::mem::size_of_val(&recv_err) as libc::socklen_t,
        );
        if res == -1 {
            panic!("{:?}", std::io::Error::last_os_error());
        }
    }

    // Spawn a separate thread for sending messages
    tokio::spawn(async move {
        // Set the destination address. This address is invalid in this context. the OS will notice
        // that nobody is listening on port 1234. Normally this is ignored (UDP is "fire and forget"),
        // but because IP_RECVERR is enabled, the error will actually be reported to the sending socket
        let mut dest_addr =
            unsafe { std::mem::MaybeUninit::<libc::sockaddr_in>::zeroed().assume_init() };
        dest_addr.sin_family = libc::AF_INET as _;
        dest_addr.sin_port = 1234u16.to_be(); // Destination port

        // Prepare the message data
        let message = "Hello, Socket!";

        // Prepare the message structure for sendmsg
        let mut iov = libc::iovec {
            iov_base: message.as_ptr() as *mut libc::c_void,
            iov_len: message.len(),
        };

        // Prepare the destination address for the sendmsg call
        let dest_sockaddr: *const libc::sockaddr = &dest_addr as *const _ as *const libc::sockaddr;
        let dest_addrlen: libc::socklen_t = std::mem::size_of_val(&dest_addr) as libc::socklen_t;

        let mut msg: libc::msghdr = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
        msg.msg_name = dest_sockaddr as *mut libc::c_void;
        msg.msg_namelen = dest_addrlen;
        msg.msg_iov = &mut iov;
        msg.msg_iovlen = 1;

        if unsafe { libc::sendmsg(socket_fd, &msg, 0) } == -1 {
            Err(std::io::Error::last_os_error()).unwrap()
        }
    });


Review comment (bug):
So this test will fail if some other test decides to use port 1234 for something?

Perhaps we should use a port number less than 1024 to avoid the case where tests using port 0 to pick a port will pick the port used by this test?

Code after:
    use tokio::io::{Interest, Ready};

    let socket_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));
    let socket = std::net::UdpSocket::bind(socket_addr).unwrap();
    let socket_fd = socket.as_raw_fd();

    // Enable IP_RECVERR option to receive error messages
    // https://man7.org/linux/man-pages/man7/ip.7.html has some extra information
    let recv_err: libc::c_int = 1;
    unsafe {
        let res = libc::setsockopt(
            socket.as_raw_fd(),
            libc::SOL_IP,
            libc::IP_RECVERR,
            &recv_err as *const _ as *const libc::c_void,
            std::mem::size_of_val(&recv_err) as libc::socklen_t,
        );
        if res == -1 {
            panic!("{:?}", std::io::Error::last_os_error());
        }
    }

    // Spawn a separate thread for sending messages
    tokio::spawn(async move {
        // Set the destination address. This address is invalid in this context. the OS will notice
        // that nobody is listening on port this port. Normally this is ignored (UDP is "fire and forget"),
        // but because IP_RECVERR is enabled, the error will actually be reported to the sending socket
        let mut dest_addr =
            unsafe { std::mem::MaybeUninit::<libc::sockaddr_in>::zeroed().assume_init() };
        dest_addr.sin_family = libc::AF_INET as _;
        // based on https://en.wikipedia.org/wiki/Ephemeral_port, we should pick a port number
        // below 1024 to guarantee that other tests don't select this port by accident when they
        // use port 0 to select an ephemeral port.
        dest_addr.sin_port = 512u16.to_be(); // Destination port

        // Prepare the message data
        let message = "Hello, Socket!";

        // Prepare the message structure for sendmsg
        let mut iov = libc::iovec {
            iov_base: message.as_ptr() as *mut libc::c_void,
            iov_len: message.len(),
        };

        // Prepare the destination address for the sendmsg call
        let dest_sockaddr: *const libc::sockaddr = &dest_addr as *const _ as *const libc::sockaddr;
        let dest_addrlen: libc::socklen_t = std::mem::size_of_val(&dest_addr) as libc::socklen_t;

        let mut msg: libc::msghdr = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
        msg.msg_name = dest_sockaddr as *mut libc::c_void;
        msg.msg_namelen = dest_addrlen;