#![allow(clippy::missing_errors_doc)] // Functions simply delegate to tokio and quinn-udp.
use std::{
io::{self, IoSliceMut},
net::SocketAddr,
slice::{self, Chunks},
};
use neqo_common::{qdebug, qtrace, Datagram, IpTos}; use quinn_udp::{EcnCodepoint, RecvMeta, Transmit, UdpSocketState};
/// Socket receive buffer size. /// /// Allows reading multiple datagrams in a single [`Socket::recv`] call. // // TODO: Experiment with different values across platforms. pubconst RECV_BUF_SIZE: usize = u16::MAX as usize;
/// A wrapper around a UDP socket, sending and receiving [`Datagram`]s. pubstruct Socket<S> {
state: UdpSocketState,
inner: S,
}
impl<S: SocketRef> Socket<S> { /// Create a new [`Socket`] given a raw file descriptor managed externally. pubfn new(socket: S) -> Result<Self, io::Error> {
Ok(Self {
state: quinn_udp::UdpSocketState::new((&socket).into())?,
inner: socket,
})
}
/// Send a [`Datagram`] on the given [`Socket`]. pubfn send(&self, d: &Datagram) -> io::Result<()> {
send_inner(&self.state, (&self.inner).into(), d)
}
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each /// set with the provided local address. pubfn recv<'a>(
&self,
local_address: SocketAddr,
recv_buf: &'a mut [u8],
) -> Result<DatagramIter<'a>, io::Error> {
recv_inner(local_address, &self.state, &self.inner, recv_buf)
}
}
#[cfg(test)] mod tests { use neqo_common::{IpTosDscp, IpTosEcn};
usesuper::*;
fn socket() -> Result<Socket<std::net::UdpSocket>, io::Error> { let socket = Socket::new(std::net::UdpSocket::bind("127.0.0.1:0")?)?; // Reverse non-blocking flag set by `UdpSocketState` to make the test non-racy.
socket.inner.set_nonblocking(false)?;
Ok(socket)
}
#[test] fn ignore_empty_datagram() -> Result<(), io::Error> { let sender = socket()?; let receiver = Socket::new(std::net::UdpSocket::bind("127.0.0.1:0")?)?; let receiver_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let datagram = Datagram::new(
sender.inner.local_addr()?,
receiver.inner.local_addr()?,
IpTos::default(),
vec![],
);
sender.send(&datagram)?; letmut recv_buf = vec![0; RECV_BUF_SIZE]; let res = receiver.recv(receiver_addr, &mut recv_buf);
assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::WouldBlock);
Ok(())
}
#[test] fn datagram_tos() -> Result<(), io::Error> { let sender = socket()?; let receiver = socket()?; let receiver_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let sender = socket()?; let receiver = socket()?; let receiver_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
// `neqo_udp::Socket::send` does not yet // (https://github.com/mozilla/neqo/issues/1693) support GSO. Use // `quinn_udp` directly. let max_gso_segments = sender.state.max_gso_segments(); let msg = vec![0xAB; SEGMENT_SIZE * max_gso_segments]; let transmit = Transmit {
destination: receiver.inner.local_addr()?,
ecn: EcnCodepoint::from_bits(Into::<u8>::into(IpTos::from((
IpTosDscp::Le,
IpTosEcn::Ect1,
)))),
contents: &msg,
segment_size: Some(SEGMENT_SIZE),
src_ip: None,
};
sender.state.try_send((&sender.inner).into(), &transmit)?;
// Allow for one GSO sendmmsg to result in multiple GRO recvmmsg. letmut num_received = 0; letmut recv_buf = vec![0; RECV_BUF_SIZE]; while num_received < max_gso_segments {
receiver
.recv(receiver_addr, &mut recv_buf)
.expect("receive to succeed")
.for_each(|d| {
assert_eq!(
SEGMENT_SIZE,
d.len(), "Expect received datagrams to have same length as sent datagrams."
);
num_received += 1;
});
}
Ok(())
}
#[test] fn fmt_datagram_iter() { let dgrams = [];
let i = DatagramIter {
meta: RecvMeta::default(),
datagrams: dgrams.chunks(1),
local_address: "[::]:0".parse().unwrap(),
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.