Distinguish PacketBuffer running out of payload space and capacity.
This makes the behavior of UdpSocket resemble that of RawSocket.v0.7.x
parent
c474d0c32e
commit
41de9c7ee0
|
@ -6,13 +6,15 @@ use storage::{PacketBuffer, PacketMetadata};
|
|||
use time::Instant;
|
||||
use wire::{IpProtocol, IpRepr, IpEndpoint, UdpRepr};
|
||||
|
||||
/// A UDP packet metadata.
|
||||
pub type UdpPacketMetadata = PacketMetadata<IpEndpoint>;
|
||||
|
||||
/// A UDP packet ring buffer.
|
||||
pub type UdpSocketBuffer<'a, 'b> = PacketBuffer<'a, 'b, IpEndpoint>;
|
||||
|
||||
/// An User Datagram Protocol socket.
|
||||
/// A User Datagram Protocol socket.
|
||||
///
|
||||
/// An UDP socket is bound to a specific endpoint, and owns transmit and receive
|
||||
/// A UDP socket is bound to a specific endpoint, and owns transmit and receive
|
||||
/// packet buffers.
|
||||
#[derive(Debug)]
|
||||
pub struct UdpSocket<'a, 'b: 'a> {
|
||||
|
@ -112,8 +114,10 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
|||
/// Enqueue a packet to be sent to a given remote endpoint, and return a pointer
|
||||
/// to its payload.
|
||||
///
|
||||
/// This function returns `Err(Error::Exhausted)` if the transmit buffer is full and
|
||||
/// `Err(Error::Unaddressable)` if local or remote port, or remote address are unspecified.
|
||||
/// This function returns `Err(Error::Exhausted)` if the transmit buffer is full,
|
||||
/// `Err(Error::Unaddressable)` if local or remote port, or remote address are unspecified,
|
||||
/// and `Err(Error::Truncated)` if there is not enough transmit buffer capacity
|
||||
/// to ever send this packet.
|
||||
pub fn send(&mut self, size: usize, endpoint: IpEndpoint) -> Result<&mut [u8]> {
|
||||
if self.endpoint.port == 0 { return Err(Error::Unaddressable) }
|
||||
if !endpoint.is_specified() { return Err(Error::Unaddressable) }
|
||||
|
@ -171,9 +175,7 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
|||
let size = repr.payload.len();
|
||||
|
||||
let endpoint = IpEndpoint { addr: ip_repr.src_addr(), port: repr.src_port };
|
||||
let payload_buf = self.rx_buffer.enqueue(size, endpoint)?;
|
||||
assert_eq!(payload_buf.len(), size);
|
||||
payload_buf.copy_from_slice(repr.payload);
|
||||
self.rx_buffer.enqueue(size, endpoint)?.copy_from_slice(repr.payload);
|
||||
|
||||
net_trace!("{}:{}:{}: receiving {} octets",
|
||||
self.meta.handle, self.endpoint,
|
||||
|
@ -457,7 +459,7 @@ mod test {
|
|||
assert_eq!(socket.bind(LOCAL_END), Ok(()));
|
||||
|
||||
let too_large = b"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefx";
|
||||
assert_eq!(socket.send_slice(too_large, REMOTE_END), Err(Error::Exhausted));
|
||||
assert_eq!(socket.send_slice(too_large, REMOTE_END), Err(Error::Truncated));
|
||||
assert_eq!(socket.send_slice(&too_large[..16*4], REMOTE_END), Ok(()));
|
||||
}
|
||||
|
||||
|
|
|
@ -72,13 +72,21 @@ impl<'a, 'b, H> PacketBuffer<'a, 'b, H> {
|
|||
|
||||
/// Enqueue a single packet with the given header into the buffer, and
|
||||
/// return a reference to its payload, or return `Err(Error::Exhausted)`
|
||||
/// if the buffer is full or does not have enough spare payload space.
|
||||
/// if the buffer is full, or return `Err(Error::Truncated)` if the buffer
|
||||
/// does not have enough spare payload space.
|
||||
pub fn enqueue(&mut self, size: usize, header: H) -> Result<&mut [u8]> {
|
||||
if self.payload_ring.capacity() < size {
|
||||
return Err(Error::Truncated)
|
||||
}
|
||||
|
||||
if self.metadata_ring.is_full() {
|
||||
return Err(Error::Exhausted)
|
||||
}
|
||||
|
||||
let window = self.payload_ring.window();
|
||||
let contig_window = self.payload_ring.contiguous_window();
|
||||
|
||||
if self.metadata_ring.is_full() || window < size ||
|
||||
(window != contig_window && window - contig_window < size) {
|
||||
if window < size || (window != contig_window && window - contig_window < size) {
|
||||
return Err(Error::Exhausted)
|
||||
}
|
||||
|
||||
|
@ -155,7 +163,7 @@ mod test {
|
|||
fn test_simple() {
|
||||
let mut buffer = buffer();
|
||||
buffer.enqueue(6, ()).unwrap().copy_from_slice(b"abcdef");
|
||||
assert_eq!(buffer.enqueue(32, ()), Err(Error::Exhausted));
|
||||
assert_eq!(buffer.enqueue(16, ()), Err(Error::Exhausted));
|
||||
assert_eq!(buffer.metadata_ring.len(), 1);
|
||||
assert_eq!(buffer.dequeue().unwrap().1, &b"abcdef"[..]);
|
||||
assert_eq!(buffer.dequeue(), Err(Error::Exhausted));
|
||||
|
@ -232,4 +240,10 @@ mod test {
|
|||
assert_eq!(buffer.enqueue(8, ()), Err(Error::Exhausted));
|
||||
assert_eq!(buffer.metadata_ring.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_capacity_too_small() {
|
||||
let mut buffer = buffer();
|
||||
assert_eq!(buffer.enqueue(32, ()), Err(Error::Truncated));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue