Skip to content

Commit

Permalink
Implement the ability for Send to act as SendTo
Browse files Browse the repository at this point in the history
This implements the equivalent of `io_uring_prep_send_set_addr`, which
was already implemented on SendZc, but not yet on the regular Send.
  • Loading branch information
ruuda committed Nov 23, 2024
1 parent 5b93270 commit 6450b10
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 deletions.
1 change: 1 addition & 0 deletions io-uring-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
tests::net::test_socket(&mut ring, &test)?;
tests::net::test_udp_recvmsg_multishot(&mut ring, &test)?;
tests::net::test_udp_recvmsg_multishot_trunc(&mut ring, &test)?;
tests::net::test_udp_send_with_dest(&mut ring, &test)?;
tests::net::test_udp_sendzc_with_dest(&mut ring, &test)?;

// queue
Expand Down
73 changes: 73 additions & 0 deletions io-uring-test/src/tests/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,79 @@ pub fn test_udp_recvmsg_multishot_trunc<S: squeue::EntryMarker, C: cqueue::Entry

Ok(())
}

pub fn test_udp_send_with_dest<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
ring: &mut IoUring<S, C>,
test: &Test,
) -> anyhow::Result<()> {
require!(
test;
test.probe.is_supported(opcode::Recv::CODE);
test.probe.is_supported(opcode::Send::CODE);
);

println!("test udp_send_with_dest");

let socket: socket2::Socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap().into();
let addr = socket.local_addr()?;
let fd = Fd(socket.as_raw_fd());

// We are going to do a send below. To confirm that it works, start a
// recv to receive the data sent by the send.
let mut in_buf = vec![0; 1024];
let recv = opcode::Recv::new(fd, in_buf.as_mut_ptr(), in_buf.len() as u32)
.build()
.user_data(1)
.into();

let out_buf = b"test message";

// For the first send, we don't specify a destination address. This should
// result in an error.
let send1 = opcode::Send::new(fd, out_buf.as_ptr(), out_buf.len() as u32)
.build()
.user_data(2)
.into();

// For the second send, we do specify the destination address, and we should
// receive our test message there.
let send2 = opcode::Send::new(fd, out_buf.as_ptr(), out_buf.len() as u32)
.dest_addr(addr.as_ptr())
.dest_addr_len(addr.len())
.build()
.user_data(3)
.into();

unsafe { ring.submission().push_multiple(&[recv, send1, send2])? };
ring.submitter().submit_and_wait(3)?;

let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
assert_eq!(cqes.len(), 3);

for cqe in cqes {
match cqe.user_data() {
1 => {
// The receive, we should have received the test message here.
let n_received = cqe.result();
assert_eq!(n_received, out_buf.len() as i32);
assert_eq!(&in_buf[..n_received as usize], out_buf);
}
2 => {
// The send should have failed because it had no destination address.
assert_eq!(cqe.result(), -libc::EDESTADDRREQ);
}
3 => {
// The send that should have succeeded.
let n_sent = cqe.result();
assert_eq!(n_sent, out_buf.len() as i32);
}
_ => unreachable!("We only submit user data 1, 2, and 3."),
}
}

Ok(())
}

pub fn test_udp_sendzc_with_dest<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
ring: &mut IoUring<S, C>,
test: &Test,
Expand Down
13 changes: 11 additions & 2 deletions src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,18 +1003,27 @@ opcode! {
buf: { *const u8 },
len: { u32 },
;;
flags: i32 = 0
flags: i32 = 0,

/// Set the destination address, for sending from an unconnected socket.
///
/// When set, `dest_addr_len` must be set as well.
/// See also `man 3 io_uring_prep_send_set_addr`.
dest_addr: *const libc::sockaddr = core::ptr::null(),
dest_addr_len: libc::socklen_t = 0,
}

pub const CODE = sys::IORING_OP_SEND;

pub fn build(self) -> Entry {
let Send { fd, buf, len, flags } = self;
let Send { fd, buf, len, flags, dest_addr, dest_addr_len } = self;

let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.__bindgen_anon_2.addr = buf as _;
sqe.__bindgen_anon_1.addr2 = dest_addr as _;
sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
sqe.len = len;
sqe.__bindgen_anon_3.msg_flags = flags as _;
Entry(sqe)
Expand Down

0 comments on commit 6450b10

Please sign in to comment.