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

Code before:
async fn await_error_readiness_timestamping() {
    use std::net::{Ipv4Addr, SocketAddr};

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

    let address_a = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));
    let address_b = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));

    let socket = std::net::UdpSocket::bind(address_a).unwrap();

    socket.set_nonblocking(true).unwrap();

    // configure send timestamps
    configure_timestamping_socket(&socket).unwrap();

    socket.connect(address_b).unwrap();

    let fd = AsyncFd::new(socket).unwrap();

    let buf = b"hello there";
    fd.get_ref().send(buf).unwrap();

    // the send timestamp should now be in the error queue
    let guard = fd.ready(Interest::ERROR).await.unwrap();
    assert_eq!(guard.ready(), Ready::ERROR);
}

#[cfg(target_os = "linux")]
fn configure_timestamping_socket(udp_socket: &std::net::UdpSocket) -> std::io::Result<libc::c_int> {
    // enable software timestamping, and specifically software send timestamping
    let options = libc::SOF_TIMESTAMPING_SOFTWARE | libc::SOF_TIMESTAMPING_TX_SOFTWARE;

    let res = unsafe {
        libc::setsockopt(
            udp_socket.as_raw_fd(),
            libc::SOL_SOCKET,
            libc::SO_TIMESTAMP,
            &options as *const _ as *const libc::c_void,
            std::mem::size_of_val(&options) as libc::socklen_t,
        )
    };

    if res == -1 {
        Err(std::io::Error::last_os_error())
    } else {
        Ok(res)
    }
}

#[tokio::test]
#[cfg(target_os = "linux")]

Review comment (suggestion):
Could we assert that the error interest is not set before we send the buffer? Currently all of our tests would pass if ERROR is always set.

Code after:
async fn await_error_readiness_timestamping() {
    use std::net::{Ipv4Addr, SocketAddr};

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

    let address_a = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));
    let address_b = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));

    let socket = std::net::UdpSocket::bind(address_a).unwrap();

    socket.set_nonblocking(true).unwrap();

    // configure send timestamps
    configure_timestamping_socket(&socket).unwrap();

    socket.connect(address_b).unwrap();

    let fd = AsyncFd::new(socket).unwrap();

    tokio::select! {
        _ = fd.ready(Interest::ERROR) => panic!(),
        _ = tokio::time::sleep(Duration::from_millis(10)) => {}
    }

    let buf = b"hello there";
    fd.get_ref().send(buf).unwrap();

    // the send timestamp should now be in the error queue
    let guard = fd.ready(Interest::ERROR).await.unwrap();
    assert_eq!(guard.ready(), Ready::ERROR);
}

#[cfg(target_os = "linux")]
fn configure_timestamping_socket(udp_socket: &std::net::UdpSocket) -> std::io::Result<libc::c_int> {
    // enable software timestamping, and specifically software send timestamping
    let options = libc::SOF_TIMESTAMPING_SOFTWARE | libc::SOF_TIMESTAMPING_TX_SOFTWARE;

    let res = unsafe {
        libc::setsockopt(
            udp_socket.as_raw_fd(),
            libc::SOL_SOCKET,
            libc::SO_TIMESTAMP,
            &options as *const _ as *const libc::c_void,
            std::mem::size_of_val(&options) as libc::socklen_t,
        )
    };

    if res == -1 {
        Err(std::io::Error::last_os_error())
    } else {
        Ok(res)