nix-rust / nix

Rust friendly bindings to *nix APIs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`sendmmsg` panics with assertion failed

kalradivyanshu opened this issue · comments

I cant get sendmmsg to work with GSO and txtime

This function uses sendmsg and works:

pub fn send_to_gso_pacing(
    socket: &tokio::net::UdpSocket,
    buf: &[u8],
    send_to: SocketAddr,
    send_at: Instant,
    segment_size: usize,
) -> io::Result<usize> {
    let iov = [IoSlice::new(buf)];
    let segment_size = segment_size as u16;
    let dst = SockaddrStorage::from(send_to);
    let sockfd = socket.as_raw_fd();

    // GSO option.
    let cmsg_gso = ControlMessage::UdpGsoSegments(&segment_size);
    let nanos_per_sec: u64 = 1_000_000_000;

    // Pacing option.
    let mut time_spec = libc::timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    unsafe {
        std::ptr::copy_nonoverlapping(
            &send_at as *const _ as *const libc::timespec,
            &mut time_spec,
            1,
        )
    };

    let send_time = time_spec.tv_sec as u64 * nanos_per_sec + time_spec.tv_nsec as u64;

    let cmsg_txtime = ControlMessage::TxTime(&send_time);

    match sendmsg::<SockaddrStorage>(
        sockfd,
        &iov,
        &[cmsg_gso, cmsg_txtime],
        MsgFlags::empty(),
        Some(&dst),
    ) {
        Ok(v) => Ok(v),
        Err(e) => Err(e.into()),
    }
}

but the same message using sendmmsg fails:

pub fn sendmmsg_to_gso_pacing(
    socket: &tokio::net::UdpSocket,
    bufs: &mut [Vec<u8>],
    send_to: SocketAddr,
    send_at: Instant,
    batch_size: usize,
    segment_size: usize,
) -> io::Result<Vec<usize>> {
    let segment_size = segment_size as u16;
    let mut iovs = Vec::with_capacity(batch_size);
    let mut addrs = Vec::with_capacity(batch_size);
    let dst = SockaddrStorage::from(send_to);
    let sockfd = socket.as_raw_fd();

    for buf in bufs {
        iovs.push([IoSlice::new(buf)]);
        addrs.push(Some(dst));
    }

    // GSO option.
    let cmsg_gso = ControlMessage::UdpGsoSegments(&segment_size);
    let nanos_per_sec: u64 = 1_000_000_000;

    // Pacing option.
    let mut time_spec = libc::timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    unsafe {
        std::ptr::copy_nonoverlapping(
            &send_at as *const _ as *const libc::timespec,
            &mut time_spec,
            1,
        )
    };

    let send_time = time_spec.tv_sec as u64 * nanos_per_sec + time_spec.tv_nsec as u64;

    let cmsg_txtime = ControlMessage::TxTime(&send_time);
    let cmsg_buffer = cmsg_space!(UdpGsoSegment, TxTime);
    println!("cmsg_buffer size: {}", cmsg_buffer.capacity());
    let mut data = MultiHeaders::preallocate(batch_size, Some(cmsg_buffer));

    match sendmmsg(
        sockfd,
        &mut data,
        &iovs,
        &addrs,
        [cmsg_gso, cmsg_txtime],
        MsgFlags::empty(),
    ) {
        Ok(v) => {
            let mut sizes = Vec::with_capacity(batch_size + 1);
            for item in v {
                sizes.push(item.bytes);
            }
            Ok(sizes)
        }
        Err(e) => Err(e.into()),
    }
}

This panics with the error:

thread 'tokio-runtime-worker' panicked at 'assertion failed: `(left != right)`
  left: `0x0`,
 right: `0x0`', path/nix-0.26.2/src/sys/socket/mod.rs:1550:13

Why does this panic? Can anyone point me to an example of how to use sendmmsg with txtime and GSO?

Thanks!