udp: update tokio_udp::UdpFramed to std::future (#1370)

This commit is contained in:
John Doneth
2019-08-14 11:18:21 -07:00
committed by Carl Lerche
parent 999a600494
commit 8d55f98f6f
6 changed files with 153 additions and 123 deletions
+4
View File
@@ -20,12 +20,16 @@ UDP bindings for tokio.
categories = ["asynchronous"] categories = ["asynchronous"]
[dependencies] [dependencies]
tokio-codec = { version = "=0.2.0-alpha.1", path = "../tokio-codec" }
# tokio-io = { version = "0.2.0", path = "../tokio-io" }
tokio-reactor = { version = "=0.2.0-alpha.1", path = "../tokio-reactor" } tokio-reactor = { version = "=0.2.0-alpha.1", path = "../tokio-reactor" }
bytes = "0.4.12"
mio = "0.6.14" mio = "0.6.14"
log = "0.4" log = "0.4"
futures-core-preview = "=0.3.0-alpha.18" futures-core-preview = "=0.3.0-alpha.18"
futures-util-preview = "=0.3.0-alpha.18" futures-util-preview = "=0.3.0-alpha.18"
futures-sink-preview = "=0.3.0-alpha.18"
[dev-dependencies] [dev-dependencies]
tokio = { version = "=0.2.0-alpha.1", path = "../tokio", default-features = false, features = ["rt-full"] } tokio = { version = "=0.2.0-alpha.1", path = "../tokio", default-features = false, features = ["rt-full"] }
+61 -39
View File
@@ -1,9 +1,12 @@
use super::UdpSocket; use super::UdpSocket;
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream}; use core::task::{Context, Poll};
use futures_core::{ready, Stream};
use futures_sink::Sink;
use log::trace; use log::trace;
use std::io; use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::pin::Pin;
use tokio_codec::{Decoder, Encoder}; use tokio_codec::{Decoder, Encoder};
/// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using /// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using
@@ -33,79 +36,98 @@ pub struct UdpFramed<C> {
flushed: bool, flushed: bool,
} }
impl<C: Decoder> Stream for UdpFramed<C> { impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
type Item = (C::Item, SocketAddr); type Item = Result<(C::Item, SocketAddr), C::Error>;
type Error = C::Error;
fn poll(&mut self) -> Poll<Option<(Self::Item)>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.rd.reserve(INITIAL_RD_CAPACITY); let pin = self.get_mut();
pin.rd.reserve(INITIAL_RD_CAPACITY);
let (n, addr) = unsafe { let (n, addr) = unsafe {
// Read into the buffer without having to initialize the memory. // Read into the buffer without having to initialize the memory.
let (n, addr) = try_ready!(self.socket.poll_recv_from(self.rd.bytes_mut())); let res = ready!(Pin::new(&mut pin.socket).poll_recv_from_priv(cx, pin.rd.bytes_mut()));
self.rd.advance_mut(n); let (n, addr) = res?;
pin.rd.advance_mut(n);
(n, addr) (n, addr)
}; };
trace!("received {} bytes, decoding", n); trace!("received {} bytes, decoding", n);
let frame_res = self.codec.decode(&mut self.rd); let frame_res = pin.codec.decode(&mut pin.rd);
self.rd.clear(); pin.rd.clear();
let frame = frame_res?; let frame = frame_res?;
let result = frame.map(|frame| (frame, addr)); // frame -> (frame, addr) let result = frame.map(|frame| Ok((frame, addr))); // frame -> (frame, addr)
trace!("frame decoded from buffer"); trace!("frame decoded from buffer");
Ok(Async::Ready(result)) Poll::Ready(result)
} }
} }
impl<C: Encoder> Sink for UdpFramed<C> { impl<C: Encoder + Unpin> Sink<(C::Item, SocketAddr)> for UdpFramed<C> {
type SinkItem = (C::Item, SocketAddr); type Error = C::Error;
type SinkError = C::Error;
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
trace!("sending frame");
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if !self.flushed { if !self.flushed {
match self.poll_complete()? { match self.poll_flush(cx)? {
Async::Ready(()) => {} Poll::Ready(()) => {}
Async::NotReady => return Ok(AsyncSink::NotReady(item)), Poll::Pending => return Poll::Pending,
} }
} }
let (frame, out_addr) = item; Poll::Ready(Ok(()))
self.codec.encode(frame, &mut self.wr)?;
self.out_addr = out_addr;
self.flushed = false;
trace!("frame encoded; length={}", self.wr.len());
Ok(AsyncSink::Ready)
} }
fn poll_complete(&mut self) -> Poll<(), C::Error> { fn start_send(self: Pin<&mut Self>, item: (C::Item, SocketAddr)) -> Result<(), Self::Error> {
trace!("sending frame");
let (frame, out_addr) = item;
let pin = self.get_mut();
pin.codec.encode(frame, &mut pin.wr)?;
pin.out_addr = out_addr;
pin.flushed = false;
trace!("frame encoded; length={}", pin.wr.len());
Ok(())
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if self.flushed { if self.flushed {
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
trace!("flushing frame; length={}", self.wr.len()); trace!("flushing frame; length={}", self.wr.len());
let n = try_ready!(self.socket.poll_send_to(&self.wr, &self.out_addr));
let Self {
ref mut socket,
ref mut out_addr,
ref mut wr,
..
} = *self;
let n = ready!(socket.poll_send_to_priv(cx, &wr, &out_addr))?;
trace!("written {}", n); trace!("written {}", n);
let wrote_all = n == self.wr.len(); let wrote_all = n == self.wr.len();
self.wr.clear(); self.wr.clear();
self.flushed = true; self.flushed = true;
if wrote_all { let res = if wrote_all {
Ok(Async::Ready(())) Ok(())
} else { } else {
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
"failed to write entire datagram to socket", "failed to write entire datagram to socket",
) )
.into()) .into())
} };
Poll::Ready(res)
} }
fn close(&mut self) -> Poll<(), C::Error> { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
try_ready!(self.poll_complete()); ready!(self.poll_flush(cx))?;
Ok(().into()) Poll::Ready(Ok(()))
} }
} }
@@ -118,8 +140,8 @@ impl<C> UdpFramed<C> {
/// See struct level documentation for more details. /// See struct level documentation for more details.
pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> { pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> {
UdpFramed { UdpFramed {
socket: socket, socket,
codec: codec, codec,
out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)), out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
rd: BytesMut::with_capacity(INITIAL_RD_CAPACITY), rd: BytesMut::with_capacity(INITIAL_RD_CAPACITY),
wr: BytesMut::with_capacity(INITIAL_WR_CAPACITY), wr: BytesMut::with_capacity(INITIAL_WR_CAPACITY),
+2 -3
View File
@@ -17,10 +17,9 @@
//! Reading and writing to it can be done using futures, which return the //! Reading and writing to it can be done using futures, which return the
//! [`Recv`], [`Send`], [`RecvFrom`] and [`SendTo`] structs respectively. //! [`Recv`], [`Send`], [`RecvFrom`] and [`SendTo`] structs respectively.
// mod frame; mod frame;
mod socket; mod socket;
pub mod split; pub mod split;
// pub use self::frame::UdpFramed; pub use self::frame::UdpFramed;
pub use self::socket::UdpSocket; pub use self::socket::UdpSocket;
+60 -51
View File
@@ -1,7 +1,11 @@
#![feature(async_await)] #![feature(async_await)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use tokio_udp::UdpSocket; use bytes::{BufMut, BytesMut};
use futures_util::{future::FutureExt, sink::SinkExt, stream::StreamExt, try_future::try_join};
use std::io;
use tokio_codec::{Decoder, Encoder};
use tokio_udp::{UdpFramed, UdpSocket};
#[tokio::test] #[tokio::test]
async fn send_recv() -> std::io::Result<()> { async fn send_recv() -> std::io::Result<()> {
@@ -72,68 +76,73 @@ async fn reunite_error() -> std::io::Result<()> {
Ok(()) Ok(())
} }
// pub struct ByteCodec; pub struct ByteCodec;
// impl Decoder for ByteCodec { impl Decoder for ByteCodec {
// type Item = Vec<u8>; type Item = Vec<u8>;
// type Error = io::Error; type Error = io::Error;
// fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Vec<u8>>, io::Error> { fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Vec<u8>>, io::Error> {
// let len = buf.len(); let len = buf.len();
// Ok(Some(buf.split_to(len).to_vec())) Ok(Some(buf.split_to(len).to_vec()))
// } }
// } }
// impl Encoder for ByteCodec { impl Encoder for ByteCodec {
// type Item = Vec<u8>; type Item = Vec<u8>;
// type Error = io::Error; type Error = io::Error;
// fn encode(&mut self, data: Vec<u8>, buf: &mut BytesMut) -> Result<(), io::Error> { fn encode(&mut self, data: Vec<u8>, buf: &mut BytesMut) -> Result<(), io::Error> {
// buf.reserve(data.len()); buf.reserve(data.len());
// buf.put(data); buf.put(data);
// Ok(()) Ok(())
// } }
// } }
// #[test] #[tokio::test]
// fn send_framed() { async fn send_framed() -> std::io::Result<()> {
// drop(env_logger::try_init()); drop(env_logger::try_init());
// let mut a_soc = t!(UdpSocket::bind(&t!("127.0.0.1:0".parse()))); let mut a_soc = UdpSocket::bind(&"127.0.0.1:0".parse().unwrap())?;
// let mut b_soc = t!(UdpSocket::bind(&t!("127.0.0.1:0".parse()))); let mut b_soc = UdpSocket::bind(&"127.0.0.1:0".parse().unwrap())?;
// let a_addr = t!(a_soc.local_addr());
// let b_addr = t!(b_soc.local_addr());
// { let a_addr = a_soc.local_addr()?;
// let a = UdpFramed::new(a_soc, ByteCodec); let b_addr = b_soc.local_addr()?;
// let b = UdpFramed::new(b_soc, ByteCodec);
// let msg = b"4567".to_vec(); // test sending & receiving bytes
{
let mut a = UdpFramed::new(a_soc, ByteCodec);
let mut b = UdpFramed::new(b_soc, ByteCodec);
// let send = a.send((msg.clone(), b_addr)); let msg = b"4567".to_vec();
// let recv = b.into_future().map_err(|e| e.0);
// let (sendt, received) = t!(send.join(recv).wait());
// let (data, addr) = received.0.unwrap(); let send = a.send((msg.clone(), b_addr));
// assert_eq!(msg, data); let recv = b.next().map(|e| e.unwrap());
// assert_eq!(a_addr, addr); let (_, received) = try_join(send, recv).await.unwrap();
// a_soc = sendt.into_inner(); let (data, addr) = received;
// b_soc = received.1.into_inner(); assert_eq!(msg, data);
// } assert_eq!(a_addr, addr);
// { a_soc = a.into_inner();
// let a = UdpFramed::new(a_soc, ByteCodec); b_soc = b.into_inner();
// let b = UdpFramed::new(b_soc, ByteCodec); }
// let msg = b"".to_vec(); // test sending & receiving an empty message
{
let mut a = UdpFramed::new(a_soc, ByteCodec);
let mut b = UdpFramed::new(b_soc, ByteCodec);
// let send = a.send((msg.clone(), b_addr)); let msg = b"".to_vec();
// let recv = b.into_future().map_err(|e| e.0);
// let received = t!(send.join(recv).wait()).1;
// let (data, addr) = received.0.unwrap(); let send = a.send((msg.clone(), b_addr));
// assert_eq!(msg, data); let recv = b.next().map(|e| e.unwrap());
// assert_eq!(a_addr, addr); let (_, received) = try_join(send, recv).await.unwrap();
// }
// } let (data, addr) = received;
assert_eq!(msg, data);
assert_eq!(a_addr, addr);
}
Ok(())
}
+24 -28
View File
@@ -10,15 +10,19 @@
#![cfg(feature = "rt-full")] #![cfg(feature = "rt-full")]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use tokio::io;
use tokio::net::UdpSocket;
use tokio::prelude::*;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::time::Duration; use std::time::Duration;
use bytes::Bytes;
use futures::{FutureExt, SinkExt, StreamExt};
use tokio::codec::BytesCodec;
use tokio::future::FutureExt as TokioFutureExt;
use tokio::io;
use tokio::net::{UdpFramed, UdpSocket};
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
let _ = env_logger::init(); let _ = env_logger::init();
@@ -27,10 +31,14 @@ async fn main() -> Result<(), Box<dyn Error>> {
let addr = addr.parse::<SocketAddr>()?; let addr = addr.parse::<SocketAddr>()?;
// Bind both our sockets and then figure out what ports we got. // Bind both our sockets and then figure out what ports we got.
let mut a = UdpSocket::bind(&addr)?; let a = UdpSocket::bind(&addr)?;
let mut b = UdpSocket::bind(&addr)?; let b = UdpSocket::bind(&addr)?;
let b_addr = b.local_addr()?; let b_addr = b.local_addr()?;
let mut a = UdpFramed::new(a, BytesCodec::new());
let mut b = UdpFramed::new(b, BytesCodec::new());
// Start off by sending a ping from a to b, afterwards we just print out // Start off by sending a ping from a to b, afterwards we just print out
// what they send us and continually send pings // what they send us and continually send pings
let a = ping(&mut a, b_addr); let a = ping(&mut a, b_addr);
@@ -48,39 +56,27 @@ async fn main() -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
async fn ping(socket: &mut UdpSocket, b_addr: SocketAddr) -> Result<(), io::Error> { async fn ping(socket: &mut UdpFramed<BytesCodec>, b_addr: SocketAddr) -> Result<(), io::Error> {
socket.send_to(b"PING", &b_addr).await?; socket.send((Bytes::from(&b"PING"[..]), b_addr)).await?;
for _ in 0..4usize { for _ in 0..4usize {
let mut buffer = [0u8; 255]; let (bytes, addr) = socket.next().map(|e| e.unwrap()).await?;
let (bytes_read, addr) = socket.recv_from(&mut buffer).await?; println!("[a] recv: {}", String::from_utf8_lossy(&bytes));
println!( socket.send((Bytes::from(&b"PING"[..]), addr)).await?;
"[a] recv: {}",
String::from_utf8_lossy(&buffer[..bytes_read])
);
socket.send_to(b"PING", &addr).await?;
} }
Ok(()) Ok(())
} }
async fn pong(socket: &mut UdpSocket) -> Result<(), io::Error> { async fn pong(socket: &mut UdpFramed<BytesCodec>) -> Result<(), io::Error> {
let mut buffer = [0u8; 255]; let timeout = Duration::from_millis(200);
while let Ok(Ok((bytes_read, addr))) = socket while let Ok(Some(Ok((bytes, addr)))) = socket.next().timeout(timeout).await {
.recv_from(&mut buffer) println!("[b] recv: {}", String::from_utf8_lossy(&bytes));
.timeout(Duration::from_millis(200))
.await
{
println!(
"[b] recv: {}",
String::from_utf8_lossy(&buffer[..bytes_read])
);
socket.send_to(b"PONG", &addr).await?; socket.send((Bytes::from(&b"PONG"[..]), addr)).await?;
} }
Ok(()) Ok(())
+2 -2
View File
@@ -58,10 +58,10 @@ pub mod udp {
//! [`Send`]: struct.Send.html //! [`Send`]: struct.Send.html
//! [`RecvFrom`]: struct.RecvFrom.html //! [`RecvFrom`]: struct.RecvFrom.html
//! [`SendTo`]: struct.SendTo.html //! [`SendTo`]: struct.SendTo.html
pub use tokio_udp::{split, UdpSocket}; pub use tokio_udp::{split, UdpFramed, UdpSocket};
} }
#[cfg(feature = "udp")] #[cfg(feature = "udp")]
pub use self::udp::UdpSocket; pub use self::udp::{UdpFramed, UdpSocket};
#[cfg(all(unix, feature = "uds"))] #[cfg(all(unix, feature = "uds"))]
pub mod unix { pub mod unix {