Mikhail Boyarsky
Mikhail Boyarsky

Reputation: 3018

Rust TcpListener failed but no errors shown

The following code is almost same as in Rust documentation for TcpListener. When the code is run on Ubuntu 14.04 it produces no errors, but at the same time it doesn't work! (netstat -an | grep ':80' or telnet both doesn't connect to this server).

If I change the port it will work. If I will add unwrap() after listen() then code will show "access denied error". I read that listen() returns IOResult<T> and if it is not used then no error will occur. But I think I use it calling acceptor.incoming() and I expect an error upon this call. Why is that not happening?

Rust version: rustc 0.13.0-nightly (bd7138dd6 2014-10-27 23:02:55 +0000)

Ubuntu 14.04

fn main() {
    let listener = TcpListener::bind("127.0.0.1", 80);

    // bind the listener to the specified address
    let mut acceptor = listener.listen(); //unwrap() here

    fn handle_client(mut stream: TcpStream) {
        println!("a");
    }
    // accept connections and process them, spawning a new tasks for each one
    for stream in acceptor.incoming() {
        match stream {
        Err(e) => { /* connection failed */ }
        Ok(stream) =>
            spawn(proc() {
                // connection succeeded
                handle_client(stream)
            })
        }
    }
    // close the socket server
    drop(acceptor); 
}

Upvotes: 2

Views: 814

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90792

The significant factor is that Listener and Acceptor are both implemented for IoResult<T> where T implements the appropriate trait. Here’s the snippet from src/libstd/io/result.rs:

impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for IoResult<L> {
    fn listen(self) -> IoResult<A> {
        match self {
            Ok(listener) => listener.listen(),
            Err(e) => Err(e),
        }
    }
}

impl<T, A: Acceptor<T>> Acceptor<T> for IoResult<A> {
    fn accept(&mut self) -> IoResult<T> {
        match *self {
            Ok(ref mut acceptor) => acceptor.accept(),
            Err(ref e) => Err(e.clone()),
        }
    }
}

Thus, TcpListener::bind returns IoResult<TcpListener>, which you can immediately call .listen() on; .listen() similarly returns IoResult<TcpAcceptor>, and Acceptor is implemented for that, so when you call .incoming() you get something that will always and immediately yield the bind or listen errors if they fail.

Upvotes: 2

Related Questions