Skip to content

Commit d970e3a

Browse files
committed
net: fix TcpSocket bugs introduced in #4270
1 parent bcb968a commit d970e3a

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

.github/workflows/ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
- valgrind
3232
- loom-compile
3333
- check-readme
34+
- test-hyper
3435
steps:
3536
- run: exit 0
3637

@@ -355,3 +356,36 @@ jobs:
355356
- name: Verify that Tokio version is up to date in README
356357
working-directory: tokio
357358
run: grep -q "$(sed '/^version = /!d' Cargo.toml | head -n1)" README.md
359+
360+
test-hyper:
361+
name: Test hyper
362+
runs-on: ubuntu-latest
363+
strategy:
364+
fail-fast: false
365+
matrix:
366+
cmd:
367+
- test
368+
- ubuntu-latest
369+
- bench
370+
steps:
371+
- uses: actions/checkout@v2
372+
- uses: actions-rs/toolchain@v1
373+
with:
374+
toolchain: ${{ env.nightly }}
375+
override: true
376+
- uses: Swatinem/rust-cache@v1
377+
- name: Test hyper
378+
run: |
379+
set -x
380+
git clone https://github.com/hyperium/hyper.git
381+
cd hyper
382+
# checkout the latest release because master maybe contains breakage.
383+
tag=$(curl -fsSL https://api.github.com/repos/hyperium/hyper/releases/latest | jq -r '.tag_name')
384+
git checkout "${tag}"
385+
echo "[workspace]" >>Cargo.toml
386+
echo "[patch.crates-io]" >>Cargo.toml
387+
echo "tokio = { path = "../tokio" }" >>Cargo.toml
388+
echo "tokio-util = { path = "../tokio-util" }" >>Cargo.toml
389+
echo "tokio-stream = { path = "../tokio-stream" }" >>Cargo.toml
390+
echo "tokio-test = { path = "../tokio-test" }" >>Cargo.toml
391+
cargo ${{ matrix.cmd }} --features full --no-fail-fast

tokio/src/net/tcp/socket.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ impl TcpSocket {
125125
socket2::Type::STREAM,
126126
Some(socket2::Protocol::TCP),
127127
)?;
128+
inner.set_nonblocking(true)?;
128129
Ok(TcpSocket { inner })
129130
}
130131

@@ -163,6 +164,7 @@ impl TcpSocket {
163164
socket2::Type::STREAM,
164165
Some(socket2::Protocol::TCP),
165166
)?;
167+
inner.set_nonblocking(true)?;
166168
Ok(TcpSocket { inner })
167169
}
168170

@@ -534,7 +536,14 @@ impl TcpSocket {
534536
/// }
535537
/// ```
536538
pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
537-
self.inner.connect(&addr.into())?;
539+
match self.inner.connect(&addr.into()) {
540+
// https://github.com/tokio-rs/mio/blob/d400ddfc97212b4a2844d741b095dab2c6d15543/src/sys/unix/tcp.rs#L31
541+
#[cfg(unix)]
542+
Err(e) if e.raw_os_error() != Some(libc::EINPROGRESS) => return Err(e),
543+
#[cfg(not(unix))]
544+
Err(e) => return Err(e),
545+
_ => {}
546+
}
538547

539548
#[cfg(windows)]
540549
let mio = unsafe { mio::net::TcpStream::from_raw_socket(self.inner.into_raw_socket()) };

tokio/tests/tcp_socket.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ async fn basic_usage_v4() {
1010
// Create server
1111
let addr = assert_ok!("127.0.0.1:0".parse());
1212
let srv = assert_ok!(TcpSocket::new_v4());
13+
assert_non_blocking(&srv);
14+
assert_close_on_exec(&srv);
1315
assert_ok!(srv.bind(addr));
1416

1517
let srv = assert_ok!(srv.listen(128));
@@ -28,6 +30,8 @@ async fn basic_usage_v6() {
2830
// Create server
2931
let addr = assert_ok!("[::1]:0".parse());
3032
let srv = assert_ok!(TcpSocket::new_v6());
33+
assert_non_blocking(&srv);
34+
assert_close_on_exec(&srv);
3135
assert_ok!(srv.bind(addr));
3236

3337
let srv = assert_ok!(srv.listen(128));
@@ -46,6 +50,8 @@ async fn bind_before_connect() {
4650
// Create server
4751
let any_addr = assert_ok!("127.0.0.1:0".parse());
4852
let srv = assert_ok!(TcpSocket::new_v4());
53+
assert_non_blocking(&srv);
54+
assert_close_on_exec(&srv);
4955
assert_ok!(srv.bind(any_addr));
5056

5157
let srv = assert_ok!(srv.listen(128));
@@ -65,10 +71,29 @@ async fn basic_linger() {
6571
// Create server
6672
let addr = assert_ok!("127.0.0.1:0".parse());
6773
let srv = assert_ok!(TcpSocket::new_v4());
74+
assert_non_blocking(&srv);
75+
assert_close_on_exec(&srv);
6876
assert_ok!(srv.bind(addr));
6977

7078
assert!(srv.linger().unwrap().is_none());
7179

7280
srv.set_linger(Some(Duration::new(0, 0))).unwrap();
7381
assert_eq!(srv.linger().unwrap(), Some(Duration::new(0, 0)));
7482
}
83+
84+
fn assert_non_blocking(socket: &TcpSocket) {
85+
#[cfg(unix)]
86+
{
87+
use std::os::unix::io::AsRawFd;
88+
let flags = unsafe { libc::fcntl(socket.as_raw_fd(), libc::F_GETFL) };
89+
assert!(flags & libc::O_NONBLOCK != 0, "O_NONBLOCK not set");
90+
}
91+
}
92+
fn assert_close_on_exec(socket: &TcpSocket) {
93+
#[cfg(unix)]
94+
{
95+
use std::os::unix::io::AsRawFd;
96+
let flags = unsafe { libc::fcntl(socket.as_raw_fd(), libc::F_GETFD) };
97+
assert!(flags & libc::FD_CLOEXEC != 0, "FD_CLOEXEC not set");
98+
}
99+
}

0 commit comments

Comments
 (0)