Skip to content
This repository was archived by the owner on Nov 7, 2019. It is now read-only.
This repository was archived by the owner on Nov 7, 2019. It is now read-only.

TcpStream's poll_close implementation doesn't close the connection #81

@Nemo157

Description

@Nemo157

This is very similar to tokio-rs/tokio#852.

Running the following test program hangs and doesn't notice that the client has closed the write side of the TcpStream:

#![feature(futures_api, async_await, await_macro)]

use std::{io, net::IpAddr};

use futures::{StreamExt, io::{AsyncReadExt, AsyncWriteExt}};
use romio::TcpListener;
use romio::TcpStream;

fn main() {
    futures::executor::block_on(async {
        let ip: IpAddr = "127.0.0.1".parse().unwrap();
        let mut listener = TcpListener::bind(&(ip, 0).into()).unwrap();

        let port = listener.local_addr().unwrap().port();

        let mut incoming = listener.incoming();
        let (_rx, mut tx) = await!(TcpStream::connect(&(ip, port).into())).unwrap().split();
        let (mut rx, _tx) = await!(incoming.next()).unwrap().unwrap().split();

        println!("Connection established");

        println!("Closing tx");
        await!(tx.close()).unwrap();

        println!("Wait for server to notice connection was closed...");
        let mut byte = [0];
        let res = await!(rx.read_exact(&mut byte));
        assert!(res.is_err());
        assert_eq!(res.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
    })
}

By adding in a wrapper around the clients TcpStream that implements poll_close to call shutdown(Shutdown::Write) the server notices that the client has closed the TCP connection

struct Fix(TcpStream);

impl AsyncRead for Fix {
    fn poll_read(&mut self, waker: &Waker, buf: &mut [u8]) -> Poll<io::Result<usize>> {
        self.0.poll_read(waker, buf)
    }
}

impl AsyncWrite for Fix {
    fn poll_write(&mut self, waker: &Waker, buf: &[u8]) -> Poll<io::Result<usize>> {
        self.0.poll_write(waker, buf)
    }

    fn poll_flush(&mut self, waker: &Waker) -> Poll<io::Result<()>> {
        self.0.poll_flush(waker)
    }

    fn poll_close(&mut self, waker: &Waker) -> Poll<io::Result<()>> {
        ready!(self.poll_flush(waker)?);
        Poll::Ready(self.0.shutdown(std::net::Shutdown::Write))
    }
}

For some reason in the linked Tokio issue they don't want to apply this change to TcpStream itself, I can't see any reason not to just change it though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions