Compare commits

...

7 commits

Author SHA1 Message Date
Stjepan Glavina
15445e3ac1 Remove re-exports in async_std::net 2019-08-23 19:29:15 +02:00
Stjepan Glavina
ddb4dc87a1 Stylistic changes 2019-08-23 19:27:10 +02:00
Stjepan Glavina
144e1c4c1b Move unit tests into the tests directory 2019-08-23 19:17:42 +02:00
DCjanus
798aa19409 replace std::net::ToSocketAddrs with async-std::net::ToSocketAddrs 2019-08-20 21:36:00 +08:00
DCjanus
d5e8d11fb9 genius hack: pretending to be impl Future 2019-08-20 21:36:00 +08:00
DCjanus
a81f7b67f7 fix documentation issue 2019-08-20 21:36:00 +08:00
DCjanus
33ba7f7e13 Implement an async version of ToSocketAddrs 2019-08-20 21:36:00 +08:00
6 changed files with 258 additions and 17 deletions

158
src/net/addr.rs Normal file
View file

@ -0,0 +1,158 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::pin::Pin;
use cfg_if::cfg_if;
use futures::future::{ready, Ready};
use crate::future::Future;
use crate::io;
use crate::task::blocking;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
macro_rules! ret {
($f:tt, $i:ty) => (ImplFuture<io::Result<$i>>);
}
} else {
macro_rules! ret {
($f:tt, $i:ty) => ($f<$i>);
}
}
}
/// A trait for objects which can be converted or resolved to one or more [`SocketAddr`] values.
///
/// This trait is an async version of [`std::net::ToSocketAddrs`].
///
/// [`std::net::ToSocketAddrs`]: https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html
pub trait ToSocketAddrs {
/// Returned iterator over socket addresses which this type may correspond to.
type Iter: Iterator<Item = SocketAddr> + Send;
/// Converts this object to an iterator of resolved `SocketAddr`s.
///
/// The returned iterator may not actually yield any values depending on the outcome of any
/// resolution performed.
///
/// Note that this function may block a backend thread while resolution is performed.
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter);
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub enum ToSocketAddrsFuture<I: Iterator<Item = SocketAddr>> {
Join(blocking::JoinHandle<io::Result<I>>),
Ready(Ready<io::Result<I>>),
}
impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<I> {
type Output = io::Result<I>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.get_mut() {
ToSocketAddrsFuture::Join(f) => Pin::new(&mut *f).poll(cx),
ToSocketAddrsFuture::Ready(f) => Pin::new(&mut *f).poll(cx),
}
}
}
impl ToSocketAddrs for SocketAddr {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for SocketAddrV4 {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for SocketAddrV6 {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for (IpAddr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for (Ipv4Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for (Ipv6Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl ToSocketAddrs for (&str, u16) {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
let host = self.0.to_string();
let port = self.1;
let join = blocking::spawn(async move {
std::net::ToSocketAddrs::to_socket_addrs(&(host.as_str(), port))
});
ToSocketAddrsFuture::Join(join)
}
}
impl ToSocketAddrs for str {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
let socket_addrs = self.to_string();
let join =
blocking::spawn(async move { std::net::ToSocketAddrs::to_socket_addrs(&socket_addrs) });
ToSocketAddrsFuture::Join(join)
}
}
impl<'a> ToSocketAddrs for &'a [SocketAddr] {
type Iter = std::iter::Cloned<std::slice::Iter<'a, SocketAddr>>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
}
}
impl<T: ToSocketAddrs + Unpin + ?Sized> ToSocketAddrs for &T {
type Iter = T::Iter;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
(**self).to_socket_addrs()
}
}
impl ToSocketAddrs for String {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!(ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrs::to_socket_addrs(self.as_str())
}
}

View file

@ -29,9 +29,11 @@
//! # }) }
//! ```
pub use addr::ToSocketAddrs;
pub use tcp::{Incoming, TcpListener, TcpStream};
pub use udp::UdpSocket;
mod addr;
pub(crate) mod driver;
mod tcp;
mod udp;

View file

@ -1,4 +1,4 @@
use std::net::{self, SocketAddr, ToSocketAddrs};
use std::net::SocketAddr;
use std::pin::Pin;
use cfg_if::cfg_if;
@ -8,6 +8,7 @@ use super::TcpStream;
use crate::future::Future;
use crate::io;
use crate::net::driver::IoHandle;
use crate::net::ToSocketAddrs;
use crate::task::{Context, Poll};
/// A TCP socket server, listening for connections.
@ -84,7 +85,7 @@ impl TcpListener {
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpListener> {
let mut last_err = None;
for addr in addrs.to_socket_addrs()? {
for addr in addrs.to_socket_addrs().await? {
match mio::net::TcpListener::bind(&addr) {
Ok(mio_listener) => {
#[cfg(unix)]
@ -241,9 +242,9 @@ impl<'a> futures::Stream for Incoming<'a> {
}
}
impl From<net::TcpListener> for TcpListener {
impl From<std::net::TcpListener> for TcpListener {
/// Converts a `std::net::TcpListener` into its asynchronous equivalent.
fn from(listener: net::TcpListener) -> TcpListener {
fn from(listener: std::net::TcpListener) -> TcpListener {
let mio_listener = mio::net::TcpListener::from_std(listener).unwrap();
#[cfg(unix)]
@ -284,7 +285,7 @@ cfg_if! {
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
net::TcpListener::from_raw_fd(fd).into()
std::net::TcpListener::from_raw_fd(fd).into()
}
}

View file

@ -1,6 +1,6 @@
use std::io::{IoSlice, IoSliceMut};
use std::mem;
use std::net::{self, SocketAddr, ToSocketAddrs};
use std::net::SocketAddr;
use std::pin::Pin;
use cfg_if::cfg_if;
@ -9,6 +9,7 @@ use futures::io::{AsyncRead, AsyncWrite};
use crate::io;
use crate::net::driver::IoHandle;
use crate::net::ToSocketAddrs;
use crate::task::{Context, Poll};
/// A TCP stream between a local and a remote socket.
@ -88,7 +89,7 @@ impl TcpStream {
let mut last_err = None;
for addr in addrs.to_socket_addrs()? {
for addr in addrs.to_socket_addrs().await? {
let mut state = {
match mio::net::TcpStream::connect(&addr) {
Ok(mio_stream) => {
@ -444,9 +445,9 @@ impl AsyncWrite for &TcpStream {
}
}
impl From<net::TcpStream> for TcpStream {
impl From<std::net::TcpStream> for TcpStream {
/// Converts a `std::net::TcpStream` into its asynchronous equivalent.
fn from(stream: net::TcpStream) -> TcpStream {
fn from(stream: std::net::TcpStream) -> TcpStream {
let mio_stream = mio::net::TcpStream::from_stream(stream).unwrap();
#[cfg(unix)]
@ -487,7 +488,7 @@ cfg_if! {
impl FromRawFd for TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
net::TcpStream::from_raw_fd(fd).into()
std::net::TcpStream::from_raw_fd(fd).into()
}
}

View file

@ -1,10 +1,12 @@
use std::io;
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use std::net::SocketAddr;
use cfg_if::cfg_if;
use futures::future;
use std::net::{Ipv4Addr, Ipv6Addr};
use crate::net::driver::IoHandle;
use crate::net::ToSocketAddrs;
use crate::task::Poll;
/// A UDP socket.
@ -77,7 +79,7 @@ impl UdpSocket {
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
let mut last_err = None;
for addr in addr.to_socket_addrs()? {
for addr in addr.to_socket_addrs().await? {
match mio::net::UdpSocket::bind(&addr) {
Ok(mio_socket) => {
#[cfg(unix)]
@ -156,7 +158,7 @@ impl UdpSocket {
/// # Ok(()) }) }
/// ```
pub async fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addrs: A) -> io::Result<usize> {
let addr = match addrs.to_socket_addrs()?.next() {
let addr = match addrs.to_socket_addrs().await?.next() {
Some(addr) => addr,
None => {
return Err(io::Error::new(
@ -243,7 +245,7 @@ impl UdpSocket {
pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> io::Result<()> {
let mut last_err = None;
for addr in addrs.to_socket_addrs()? {
for addr in addrs.to_socket_addrs().await? {
match self.io_handle.get_ref().connect(addr) {
Ok(()) => return Ok(()),
Err(err) => last_err = Some(err),
@ -516,9 +518,9 @@ impl UdpSocket {
}
}
impl From<net::UdpSocket> for UdpSocket {
impl From<std::net::UdpSocket> for UdpSocket {
/// Converts a `std::net::UdpSocket` into its asynchronous equivalent.
fn from(socket: net::UdpSocket) -> UdpSocket {
fn from(socket: std::net::UdpSocket) -> UdpSocket {
let mio_socket = mio::net::UdpSocket::from_socket(socket).unwrap();
#[cfg(unix)]
@ -559,7 +561,7 @@ cfg_if! {
impl FromRawFd for UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
net::UdpSocket::from_raw_fd(fd).into()
std::net::UdpSocket::from_raw_fd(fd).into()
}
}

77
tests/addr.rs Normal file
View file

@ -0,0 +1,77 @@
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use async_std::net::ToSocketAddrs;
use async_std::task;
fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
let socket_addrs = task::block_on(a.to_socket_addrs());
match socket_addrs {
Ok(a) => Ok(a.collect()),
Err(e) => Err(e.to_string()),
}
}
pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
SocketAddr::V4(SocketAddrV4::new(a, p))
}
pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
}
#[test]
fn to_socket_addr_ipaddr_u16() {
let a = Ipv4Addr::new(77, 88, 21, 11);
let p = 12345;
let e = SocketAddr::V4(SocketAddrV4::new(a, p));
assert_eq!(Ok(vec![e]), tsa((a, p)));
}
#[test]
fn to_socket_addr_str_u16() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_str() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa("localhost:23924").unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_string() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
let s = format!("{}:{}", "77.88.21.11", "24352");
assert_eq!(Ok(vec![a]), tsa(s));
// s has been moved into the tsa call
}
// FIXME: figure out why this fails on openbsd and fix it
#[test]
#[cfg(not(any(windows, target_os = "openbsd")))]
fn to_socket_addr_str_bad() {
assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
}