Skip to content

Commit bba7730

Browse files
authored
Implement the ability for Send to act as SendTo (#309)
This implements the equivalent of `io_uring_prep_send_set_addr`, which was already implemented on SendZc, but not yet on the regular Send.
1 parent 5b93270 commit bba7730

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

io-uring-test/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
134134
tests::net::test_socket(&mut ring, &test)?;
135135
tests::net::test_udp_recvmsg_multishot(&mut ring, &test)?;
136136
tests::net::test_udp_recvmsg_multishot_trunc(&mut ring, &test)?;
137+
tests::net::test_udp_send_with_dest(&mut ring, &test)?;
137138
tests::net::test_udp_sendzc_with_dest(&mut ring, &test)?;
138139

139140
// queue

io-uring-test/src/tests/net.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,79 @@ pub fn test_udp_recvmsg_multishot_trunc<S: squeue::EntryMarker, C: cqueue::Entry
15751575

15761576
Ok(())
15771577
}
1578+
1579+
pub fn test_udp_send_with_dest<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
1580+
ring: &mut IoUring<S, C>,
1581+
test: &Test,
1582+
) -> anyhow::Result<()> {
1583+
require!(
1584+
test;
1585+
test.probe.is_supported(opcode::Recv::CODE);
1586+
test.probe.is_supported(opcode::Send::CODE);
1587+
);
1588+
1589+
println!("test udp_send_with_dest");
1590+
1591+
let socket: socket2::Socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap().into();
1592+
let addr = socket.local_addr()?;
1593+
let fd = Fd(socket.as_raw_fd());
1594+
1595+
// We are going to do a send below. To confirm that it works, start a
1596+
// recv to receive the data sent by the send.
1597+
let mut in_buf = vec![0; 1024];
1598+
let recv = opcode::Recv::new(fd, in_buf.as_mut_ptr(), in_buf.len() as u32)
1599+
.build()
1600+
.user_data(1)
1601+
.into();
1602+
1603+
let out_buf = b"test message";
1604+
1605+
// For the first send, we don't specify a destination address. This should
1606+
// result in an error.
1607+
let send1 = opcode::Send::new(fd, out_buf.as_ptr(), out_buf.len() as u32)
1608+
.build()
1609+
.user_data(2)
1610+
.into();
1611+
1612+
// For the second send, we do specify the destination address, and we should
1613+
// receive our test message there.
1614+
let send2 = opcode::Send::new(fd, out_buf.as_ptr(), out_buf.len() as u32)
1615+
.dest_addr(addr.as_ptr())
1616+
.dest_addr_len(addr.len())
1617+
.build()
1618+
.user_data(3)
1619+
.into();
1620+
1621+
unsafe { ring.submission().push_multiple(&[recv, send1, send2])? };
1622+
ring.submitter().submit_and_wait(3)?;
1623+
1624+
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
1625+
assert_eq!(cqes.len(), 3);
1626+
1627+
for cqe in cqes {
1628+
match cqe.user_data() {
1629+
1 => {
1630+
// The receive, we should have received the test message here.
1631+
let n_received = cqe.result();
1632+
assert_eq!(n_received, out_buf.len() as i32);
1633+
assert_eq!(&in_buf[..n_received as usize], out_buf);
1634+
}
1635+
2 => {
1636+
// The send should have failed because it had no destination address.
1637+
assert_eq!(cqe.result(), -libc::EDESTADDRREQ);
1638+
}
1639+
3 => {
1640+
// The send that should have succeeded.
1641+
let n_sent = cqe.result();
1642+
assert_eq!(n_sent, out_buf.len() as i32);
1643+
}
1644+
_ => unreachable!("We only submit user data 1, 2, and 3."),
1645+
}
1646+
}
1647+
1648+
Ok(())
1649+
}
1650+
15781651
pub fn test_udp_sendzc_with_dest<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
15791652
ring: &mut IoUring<S, C>,
15801653
test: &Test,

src/opcode.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,18 +1003,27 @@ opcode! {
10031003
buf: { *const u8 },
10041004
len: { u32 },
10051005
;;
1006-
flags: i32 = 0
1006+
flags: i32 = 0,
1007+
1008+
/// Set the destination address, for sending from an unconnected socket.
1009+
///
1010+
/// When set, `dest_addr_len` must be set as well.
1011+
/// See also `man 3 io_uring_prep_send_set_addr`.
1012+
dest_addr: *const libc::sockaddr = core::ptr::null(),
1013+
dest_addr_len: libc::socklen_t = 0,
10071014
}
10081015

10091016
pub const CODE = sys::IORING_OP_SEND;
10101017

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

10141021
let mut sqe = sqe_zeroed();
10151022
sqe.opcode = Self::CODE;
10161023
assign_fd!(sqe.fd = fd);
10171024
sqe.__bindgen_anon_2.addr = buf as _;
1025+
sqe.__bindgen_anon_1.addr2 = dest_addr as _;
1026+
sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
10181027
sqe.len = len;
10191028
sqe.__bindgen_anon_3.msg_flags = flags as _;
10201029
Entry(sqe)

0 commit comments

Comments
 (0)