Skip to content

Commit 1d87583

Browse files
author
Stjepan Glavina
authored
Implement Clone for TcpStream (#689)
* Implement Clone for TcpStream * Update examples * Remove accidentally added examples
1 parent 57974ae commit 1d87583

File tree

5 files changed

+47
-18
lines changed

5 files changed

+47
-18
lines changed

examples/tcp-echo.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use async_std::task;
1414
async fn process(stream: TcpStream) -> io::Result<()> {
1515
println!("Accepted from: {}", stream.peer_addr()?);
1616

17-
let (reader, writer) = &mut (&stream, &stream);
18-
io::copy(reader, writer).await?;
17+
let mut reader = stream.clone();
18+
let mut writer = stream;
19+
io::copy(&mut reader, &mut writer).await?;
1920

2021
Ok(())
2122
}

examples/tcp-ipv4-and-6-echo.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ use async_std::task;
1515
async fn process(stream: TcpStream) -> io::Result<()> {
1616
println!("Accepted from: {}", stream.peer_addr()?);
1717

18-
let (reader, writer) = &mut (&stream, &stream);
19-
io::copy(reader, writer).await?;
18+
let mut reader = stream.clone();
19+
let mut writer = stream;
20+
io::copy(&mut reader, &mut writer).await?;
2021

2122
Ok(())
2223
}

src/net/tcp/listener.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::future::Future;
22
use std::net::SocketAddr;
33
use std::pin::Pin;
4+
use std::sync::Arc;
45

56
use crate::future;
67
use crate::io;
@@ -75,9 +76,7 @@ impl TcpListener {
7576
/// [`local_addr`]: #method.local_addr
7677
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpListener> {
7778
let mut last_err = None;
78-
let addrs = addrs
79-
.to_socket_addrs()
80-
.await?;
79+
let addrs = addrs.to_socket_addrs().await?;
8180

8281
for addr in addrs {
8382
match mio::net::TcpListener::bind(&addr) {
@@ -121,7 +120,7 @@ impl TcpListener {
121120

122121
let mio_stream = mio::net::TcpStream::from_stream(io)?;
123122
let stream = TcpStream {
124-
watcher: Watcher::new(mio_stream),
123+
watcher: Arc::new(Watcher::new(mio_stream)),
125124
};
126125
Ok((stream, addr))
127126
}

src/net/tcp/stream.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::io::{IoSlice, IoSliceMut, Read as _, Write as _};
22
use std::net::SocketAddr;
33
use std::pin::Pin;
4+
use std::sync::Arc;
45

56
use crate::future;
67
use crate::io::{self, Read, Write};
@@ -44,9 +45,9 @@ use crate::task::{Context, Poll};
4445
/// #
4546
/// # Ok(()) }) }
4647
/// ```
47-
#[derive(Debug)]
48+
#[derive(Debug, Clone)]
4849
pub struct TcpStream {
49-
pub(super) watcher: Watcher<mio::net::TcpStream>,
50+
pub(super) watcher: Arc<Watcher<mio::net::TcpStream>>,
5051
}
5152

5253
impl TcpStream {
@@ -71,9 +72,7 @@ impl TcpStream {
7172
/// ```
7273
pub async fn connect<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpStream> {
7374
let mut last_err = None;
74-
let addrs = addrs
75-
.to_socket_addrs()
76-
.await?;
75+
let addrs = addrs.to_socket_addrs().await?;
7776

7877
for addr in addrs {
7978
// mio's TcpStream::connect is non-blocking and may just be in progress
@@ -84,16 +83,20 @@ impl TcpStream {
8483
Ok(s) => Watcher::new(s),
8584
Err(e) => {
8685
last_err = Some(e);
87-
continue
86+
continue;
8887
}
8988
};
9089

9190
future::poll_fn(|cx| watcher.poll_write_ready(cx)).await;
9291

9392
match watcher.get_ref().take_error() {
94-
Ok(None) => return Ok(TcpStream { watcher }),
93+
Ok(None) => {
94+
return Ok(TcpStream {
95+
watcher: Arc::new(watcher),
96+
});
97+
}
9598
Ok(Some(e)) => last_err = Some(e),
96-
Err(e) => last_err = Some(e)
99+
Err(e) => last_err = Some(e),
97100
}
98101
}
99102

@@ -369,7 +372,7 @@ impl From<std::net::TcpStream> for TcpStream {
369372
fn from(stream: std::net::TcpStream) -> TcpStream {
370373
let mio_stream = mio::net::TcpStream::from_stream(stream).unwrap();
371374
TcpStream {
372-
watcher: Watcher::new(mio_stream),
375+
watcher: Arc::new(Watcher::new(mio_stream)),
373376
}
374377
}
375378
}
@@ -391,7 +394,10 @@ cfg_unix! {
391394

392395
impl IntoRawFd for TcpStream {
393396
fn into_raw_fd(self) -> RawFd {
394-
self.watcher.into_inner().into_raw_fd()
397+
// TODO(stjepang): This does not mean `RawFd` is now the sole owner of the file
398+
// descriptor because it's possible that there are other clones of this `TcpStream`
399+
// using it at the same time. We should probably document that behavior.
400+
self.as_raw_fd()
395401
}
396402
}
397403
}

tests/tcp.rs

+22
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,25 @@ fn smoke_async_stream_to_std_listener() -> io::Result<()> {
9494

9595
Ok(())
9696
}
97+
98+
#[test]
99+
fn cloned_streams() -> io::Result<()> {
100+
task::block_on(async {
101+
let listener = TcpListener::bind("127.0.0.1:0").await?;
102+
let addr = listener.local_addr()?;
103+
104+
let mut stream = TcpStream::connect(&addr).await?;
105+
let mut cloned_stream = stream.clone();
106+
let mut incoming = listener.incoming();
107+
let mut write_stream = incoming.next().await.unwrap()?;
108+
write_stream.write_all(b"Each your doing").await?;
109+
110+
let mut buf = [0; 15];
111+
stream.read_exact(&mut buf[..8]).await?;
112+
cloned_stream.read_exact(&mut buf[8..]).await?;
113+
114+
assert_eq!(&buf[..15], b"Each your doing");
115+
116+
Ok(())
117+
})
118+
}

0 commit comments

Comments
 (0)